2
0
mirror of https://github.com/frappe/books.git synced 2025-01-22 14:48:25 +00:00

foreign keys

This commit is contained in:
Rushabh Mehta 2018-02-20 15:23:38 +05:30
parent 61294fd77f
commit 742b933207
6 changed files with 124 additions and 32 deletions

View File

@ -30,54 +30,90 @@ module.exports = class Database extends Observable {
await this.commit();
}
async createTable(doctype) {
async createTable(doctype, newName=null) {
let meta = frappe.getMeta(doctype);
let columns = [];
let values = [];
let indexes = [];
for (let field of meta.getValidFields({ withChildren: false })) {
if (this.type_map[field.fieldtype]) {
columns.push(this.getColumnDefinition(field));
this.updateColumnDefinition(field, columns, indexes);
}
}
return await this.runCreateTableQuery(doctype, columns, values);
return await this.runCreateTableQuery(newName || doctype, columns, indexes);
}
async tableExists(table) {
// return true if table exists
}
async runCreateTableQuery(doctype, columns, values) {
async runCreateTableQuery(doctype, columns, indexes) {
// override
}
getColumnDefinition(df) {
updateColumnDefinition(field, columns, indexes) {
// return `${df.fieldname} ${this.type_map[df.fieldtype]} ${ ? "PRIMARY KEY" : ""} ${df.required && !df.default ? "NOT NULL" : ""} ${df.default ? `DEFAULT ${df.default}` : ""}`
}
async alterTable(doctype) {
// get columns
let newColumns = await this.getNewColumns(doctype);
let newForeignKeys = await this.getNewForeignKeys(doctype);
if (newColumns.length) {
await this.addColumns(doctype, newColumns);
}
if (newForeignKeys.length) {
await this.addForeignKeys(doctype);
}
}
async getNewColumns(doctype) {
let tableColumns = await this.getTableColumns(doctype);
let meta = frappe.getMeta(doctype);
let values = [];
let newColumns = [];
for (let field of meta.getValidFields({ withChildren: false })) {
if (!tableColumns.includes(field.fieldname) && this.type_map[field.fieldtype]) {
values = []
if (field.default) {
values.push(field.default);
}
await this.runAlterTableQuery(doctype, field, values);
newColumns.push(field);
}
}
return newColumns;
}
async addColumns(doctype, newColumns) {
for (let field of newColumns) {
await this.runAddColumnQuery(doctype, field);
}
}
async getNewForeignKeys(doctype) {
let foreignKeys = await this.getForeignKeys(doctype);
let newForeignKeys = [];
let meta = frappe.getMeta(doctype);
for (let field of meta.getValidFields({ withChildren: false})) {
if (field.fieldtype==='Link' && !foreignKeys.includes(field.fieldname)) {
newForeignKeys.push(field);
}
}
return newForeignKeys;
}
async addForeignKeys(doctype, newForeignKeys) {
for (let field of newForeignKeys) {
this.addForeignKey(doctype, field);
}
}
async getForeignKey(doctype, field) {
}
async getTableColumns(doctype) {
return [];
}
async runAlterTableQuery(doctype, field, values) {
async runAddColumnQuery(doctype, field) {
// alter table {doctype} add column ({column_def});
}

View File

@ -52,8 +52,8 @@ module.exports = class mysqlDatabase extends Database{
}
getColumnDefinition(df) {
return `${df.fieldname} ${this.type_map[df.fieldtype]} ${df.reqd && !df.default ? "not null" : ""} ${df.default ? `default '${df.default}'` : ""}`
updateColumnDefinition(df, columns, indexes) {
columns.push(`${df.fieldname} ${this.type_map[df.fieldtype]} ${df.reqd && !df.default ? "not null" : ""} ${df.default ? `default '${df.default}'` : ""}`);
}
async getTableColumns(doctype) {
@ -61,7 +61,7 @@ module.exports = class mysqlDatabase extends Database{
}
async runAlterTableQuery(doctype) {
async runAddColumnQuery(doctype) {
await this.run(`ALTER TABLE ${doctype} ADD COLUMN ${this.get_column_definition(df)}`, values);
}

View File

@ -18,7 +18,7 @@ module.exports = class sqliteDatabase extends Database {
if (debug) {
this.conn.on('trace', (trace) => console.log(trace));
}
resolve();
this.run('PRAGMA foreign_keys=ON').then(resolve);
});
});
}
@ -28,22 +28,70 @@ module.exports = class sqliteDatabase extends Database {
return (name && name.length) ? true : false;
}
async runCreateTableQuery(doctype, columns, values) {
const query = `CREATE TABLE IF NOT EXISTS ${doctype} (
${columns.join(", ")})`;
async alterTable(doctype) {
let newColumns = await this.getNewColumns(doctype);
let newForeignKeys = await this.getNewForeignKeys(doctype);
return await this.run(query, values);
if (newColumns.length || newForeignKeys.length) {
await this.migrateToNewTable(doctype);
}
}
getColumnDefinition(df) {
return `${df.fieldname} ${this.type_map[df.fieldtype]} ${ df.fieldname==="name" ? "PRIMARY KEY" : ""} ${df.required && !df.default ? "NOT NULL" : ""} ${df.default ? `DEFAULT ${df.default}` : ""}`
async migrateToNewTable(doctype) {
await this.run('PRAGMA foreign_keys=OFF');
await this.run('BEGIN TRANSACTION');
// create temp table
await this.createTable(doctype, 'TEMP' + doctype);
// copy from old to new table
await this.run(`INSERT INTO TEMP${doctype} SELECT * from ${doctype}`);
// drop old table
await this.run(`DROP TABLE ${doctype}`);
// rename new table
await this.run(`ALTER TABLE TEMP${doctype} RENAME TO ${doctype}`);
await this.run('COMMIT');
await this.run('PRAGMA foreign_keys=ON');
}
async runCreateTableQuery(doctype, columns, indexes) {
const query = `CREATE TABLE IF NOT EXISTS ${doctype} (
${columns.join(", ")} ${indexes.length ? (", " + indexes.join(", ")) : ''})`;
return await this.run(query);
}
updateColumnDefinition(field, columns, indexes) {
let def = `${field.fieldname} ${this.type_map[field.fieldtype]}`;
if (field.fieldname==='name') {
def += ' PRIMARY KEY NOT NULL';
}
else if (field.reqd) {
def += ' NOT NULL';
}
if (field.default) {
def += `DEFAULT ${field.default}`;
}
columns.push(def);
if (field.fieldtype==='Link' && field.target) {
indexes.push(`FOREIGN KEY (${field.fieldname}) REFERENCES ${field.target} ON UPDATE RESTRICT ON DELETE RESTRICT`);
}
}
async getTableColumns(doctype) {
return (await this.sql(`PRAGMA table_info(${doctype})`)).map(d => d.name);
}
async runAlterTableQuery(doctype, field, values) {
async getForeignKeys(doctype) {
return (await this.sql(`PRAGMA foreign_key_list(${doctype})`)).map(d => d.from);
}
async runAddColumnQuery(doctype, field, values) {
await this.run(`ALTER TABLE ${doctype} ADD COLUMN ${this.getColumnDefinition(field)}`, values);
}

View File

@ -52,9 +52,7 @@ module.exports = class BaseForm extends Observable {
if (!this.meta.isSingle && this.actions.includes('delete')) {
let menu = this.container.getDropdown(frappe._('Menu'));
menu.addItem(frappe._("Delete"), async (e) => {
await this.doc.delete();
this.showAlert('Deleted', 'success');
this.trigger('delete');
await this.delete();
});
}
@ -178,6 +176,16 @@ module.exports = class BaseForm extends Observable {
await this.trigger('submit');
}
async delete() {
try {
await this.doc.delete();
this.showAlert('Deleted', 'success');
this.trigger('delete');
} catch (e) {
this.showAlert(e, 'danger');
}
}
refresh() {
for(let control of this.controlList) {
control.refresh();

View File

@ -133,7 +133,7 @@ module.exports = class BaseDocument extends Observable {
this.owner = frappe.session.user;
this.creation = now;
}
this.modified_by = frappe.session.user;
this.modifieldBy = frappe.session.user;
this.modified = now;
}

View File

@ -22,10 +22,10 @@ module.exports = {
],
parent_fields: [
{
fieldname: 'owner', fieldtype: 'Link', required: 1, options: 'User'
fieldname: 'owner', fieldtype: 'Text', required: 1
},
{
fieldname: 'modified_by', fieldtype: 'Link', required: 1, options: 'User'
fieldname: 'modifieldBy', fieldtype: 'Text', required: 1
},
{
fieldname: 'creation', fieldtype: 'Datetime', required: 1
@ -48,7 +48,7 @@ module.exports = {
fieldname: 'parent', fieldtype: 'Data', required: 1
},
{
fieldname: 'parenttype', fieldtype: 'Link', required: 1, options: 'DocType'
fieldname: 'parenttype', fieldtype: 'Text', required: 1
},
{
fieldname: 'parentfield', fieldtype: 'Data', required: 1