mirror of
https://github.com/n8n-io/n8n.git
synced 2024-08-17 00:50:42 +03:00
Added support for MySQL
* In packages/cli/src/Db.ts, conditional test of dbType replaced by a switch; * removeAll() function adapted to not cause an error using MySQL; * Added the cross-env module in the "serve" script in the packages/editor-ui/package.json file. This was done to ensure compatibility between platforms when declaring environment variables. Without it, Windows compilation would give an error, for example; * .idea added to .gitignore (IntelliJ IDEA solutions);
This commit is contained in:
parent
1777f171bd
commit
3bdd9096e1
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,3 +11,4 @@ google-generated-credentials.json
|
||||
_START_PACKAGE
|
||||
.env
|
||||
.vscode
|
||||
.idea
|
||||
|
@ -8,7 +8,7 @@ const config = convict({
|
||||
database: {
|
||||
type: {
|
||||
doc: 'Type of database to use',
|
||||
format: ['sqlite', 'mongodb', 'postgresdb'],
|
||||
format: ['sqlite', 'mongodb', 'mysqldb', 'postgresdb'],
|
||||
default: 'sqlite',
|
||||
env: 'DB_TYPE'
|
||||
},
|
||||
@ -52,6 +52,38 @@ const config = convict({
|
||||
env: 'DB_POSTGRESDB_USER'
|
||||
},
|
||||
},
|
||||
mysqldb: {
|
||||
database: {
|
||||
doc: 'MySQL Database',
|
||||
format: String,
|
||||
default: 'n8n',
|
||||
env: 'DB_MYSQLDB_DATABASE'
|
||||
},
|
||||
host: {
|
||||
doc: 'MySQL Host',
|
||||
format: String,
|
||||
default: 'localhost',
|
||||
env: 'DB_MYSQLDB_HOST'
|
||||
},
|
||||
password: {
|
||||
doc: 'MySQL Password',
|
||||
format: String,
|
||||
default: '',
|
||||
env: 'DB_MYSQLDB_PASSWORD'
|
||||
},
|
||||
port: {
|
||||
doc: 'MySQL Port',
|
||||
format: Number,
|
||||
default: 5432,
|
||||
env: 'DB_MYSQLDB_PORT'
|
||||
},
|
||||
user: {
|
||||
doc: 'MySQL User',
|
||||
format: String,
|
||||
default: 'root',
|
||||
env: 'DB_MYSQLDB_USER'
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
executions: {
|
||||
|
@ -18,6 +18,7 @@ import {
|
||||
MongoDb,
|
||||
PostgresDb,
|
||||
SQLite,
|
||||
MySQLDb,
|
||||
} from './databases';
|
||||
|
||||
export let collections: IDatabaseCollections = {
|
||||
@ -36,33 +37,53 @@ export async function init(synchronize?: boolean): Promise<IDatabaseCollections>
|
||||
let connectionOptions: ConnectionOptions;
|
||||
|
||||
let dbNotExistError: string | undefined;
|
||||
if (dbType === 'mongodb') {
|
||||
entities = MongoDb;
|
||||
connectionOptions = {
|
||||
type: 'mongodb',
|
||||
url: await GenericHelpers.getConfigValue('database.mongodb.connectionUrl') as string,
|
||||
useNewUrlParser: true,
|
||||
};
|
||||
} else if (dbType === 'postgresdb') {
|
||||
dbNotExistError = 'does not exist';
|
||||
entities = PostgresDb;
|
||||
connectionOptions = {
|
||||
type: 'postgres',
|
||||
database: await GenericHelpers.getConfigValue('database.postgresdb.database') as string,
|
||||
host: await GenericHelpers.getConfigValue('database.postgresdb.host') as string,
|
||||
password: await GenericHelpers.getConfigValue('database.postgresdb.password') as string,
|
||||
port: await GenericHelpers.getConfigValue('database.postgresdb.port') as number,
|
||||
username: await GenericHelpers.getConfigValue('database.postgresdb.user') as string,
|
||||
};
|
||||
} else if (dbType === 'sqlite') {
|
||||
dbNotExistError = 'no such table:';
|
||||
entities = SQLite;
|
||||
connectionOptions = {
|
||||
type: 'sqlite',
|
||||
database: path.join(n8nFolder, 'database.sqlite'),
|
||||
};
|
||||
} else {
|
||||
throw new Error(`The database "${dbType}" is currently not supported!`);
|
||||
switch (dbType) {
|
||||
case 'mongodb':
|
||||
entities = MongoDb;
|
||||
connectionOptions = {
|
||||
type: 'mongodb',
|
||||
url: await GenericHelpers.getConfigValue('database.mongodb.connectionUrl') as string,
|
||||
useNewUrlParser: true,
|
||||
};
|
||||
break;
|
||||
|
||||
case 'postgresdb':
|
||||
dbNotExistError = 'does not exist';
|
||||
entities = PostgresDb;
|
||||
connectionOptions = {
|
||||
type: 'postgres',
|
||||
database: await GenericHelpers.getConfigValue('database.postgresdb.database') as string,
|
||||
host: await GenericHelpers.getConfigValue('database.postgresdb.host') as string,
|
||||
password: await GenericHelpers.getConfigValue('database.postgresdb.password') as string,
|
||||
port: await GenericHelpers.getConfigValue('database.postgresdb.port') as number,
|
||||
username: await GenericHelpers.getConfigValue('database.postgresdb.user') as string,
|
||||
};
|
||||
break;
|
||||
|
||||
case 'mysqldb':
|
||||
dbNotExistError = 'does not exist';
|
||||
entities = MySQLDb;
|
||||
connectionOptions = {
|
||||
type: 'mysql',
|
||||
database: await GenericHelpers.getConfigValue('database.mysqldb.database') as string,
|
||||
host: await GenericHelpers.getConfigValue('database.mysqldb.host') as string,
|
||||
password: await GenericHelpers.getConfigValue('database.mysqldb.password') as string,
|
||||
port: await GenericHelpers.getConfigValue('database.mysqldb.port') as number,
|
||||
username: await GenericHelpers.getConfigValue('database.mysqldb.user') as string
|
||||
};
|
||||
break;
|
||||
|
||||
case 'sqlite':
|
||||
dbNotExistError = 'no such table:';
|
||||
entities = SQLite;
|
||||
connectionOptions = {
|
||||
type: 'sqlite',
|
||||
database: path.join(n8nFolder, 'database.sqlite'),
|
||||
};
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`The database "${dbType}" is currently not supported!`);
|
||||
}
|
||||
|
||||
Object.assign(connectionOptions, {
|
||||
|
@ -87,7 +87,7 @@ export interface ICredentialsDecryptedResponse extends ICredentialsDecryptedDb {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export type DatabaseType = 'mongodb' | 'postgresdb' | 'sqlite';
|
||||
export type DatabaseType = 'mongodb' | 'postgresdb' | 'mysqldb' | 'sqlite';
|
||||
export type SaveExecutionDataType = 'all' | 'none';
|
||||
|
||||
export interface IExecutionBase {
|
||||
|
@ -208,26 +208,32 @@ export class TestWebhooks {
|
||||
}
|
||||
const nodeTypes = NodeTypes();
|
||||
|
||||
const findQuery = {
|
||||
where: {
|
||||
id: findIn(this.activeWebhooks.getWorkflowIds())
|
||||
},
|
||||
} as FindManyOptions;
|
||||
/*
|
||||
* Here I check first if WorkflowIds is empty. This is done because when entering an empty array for TypeORM's In option, a syntax error is generated in MySQL.
|
||||
* Because the SQL is: ... FROM `workflow_entity`` WorkflowEntity` WHERE `WorkflowEntity`.`id` IN ()
|
||||
*
|
||||
* The empty IN function is not accepted in MySQL.
|
||||
*/
|
||||
const WorkflowIds = this.activeWebhooks.getWorkflowIds();
|
||||
if (WorkflowIds.length > 0) {
|
||||
const findQuery = {
|
||||
where: {
|
||||
id: findIn(WorkflowIds)
|
||||
},
|
||||
} as FindManyOptions;
|
||||
|
||||
const workflowsDb = await Db.collections.Workflow!.find(findQuery);
|
||||
const workflows: Workflow[] = [];
|
||||
for (const workflowData of workflowsDb) {
|
||||
const workflow = new Workflow(workflowData.id.toString(), workflowData.nodes, workflowData.connections, workflowData.active, nodeTypes, workflowData.staticData, workflowData.settings);
|
||||
workflows.push(workflow);
|
||||
const workflowsDb = await Db.collections.Workflow!.find(findQuery);
|
||||
const workflows: Workflow[] = [];
|
||||
for (const workflowData of workflowsDb) {
|
||||
const workflow = new Workflow(workflowData.id.toString(), workflowData.nodes, workflowData.connections, workflowData.active, nodeTypes, workflowData.staticData, workflowData.settings);
|
||||
workflows.push(workflow);
|
||||
}
|
||||
|
||||
return this.activeWebhooks.removeAll(workflows);
|
||||
}
|
||||
|
||||
return this.activeWebhooks.removeAll(workflows);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
let testWebhooksInstance: TestWebhooks | undefined;
|
||||
|
||||
export function getInstance(): TestWebhooks {
|
||||
|
@ -1,9 +1,11 @@
|
||||
import * as MongoDb from './mongodb';
|
||||
import * as PostgresDb from './postgresdb';
|
||||
import * as SQLite from './sqlite';
|
||||
import * as MySQLDb from './mysqldb';
|
||||
|
||||
export {
|
||||
MongoDb,
|
||||
PostgresDb,
|
||||
SQLite,
|
||||
MySQLDb,
|
||||
};
|
||||
|
44
packages/cli/src/databases/mysqldb/CredentialsEntity.ts
Normal file
44
packages/cli/src/databases/mysqldb/CredentialsEntity.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import {
|
||||
ICredentialNodeAccess,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
ICredentialsDb,
|
||||
} from '../../';
|
||||
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
Index,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
@Entity()
|
||||
export class CredentialsEntity implements ICredentialsDb {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({
|
||||
length: 128
|
||||
})
|
||||
name: string;
|
||||
|
||||
@Column('text')
|
||||
data: string;
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
length: 32
|
||||
})
|
||||
type: string;
|
||||
|
||||
@Column('json')
|
||||
nodesAccess: ICredentialNodeAccess[];
|
||||
|
||||
@Column('timestamp')
|
||||
createdAt: Date;
|
||||
|
||||
@Column('timestamp')
|
||||
updatedAt: Date;
|
||||
}
|
51
packages/cli/src/databases/mysqldb/ExecutionEntity.ts
Normal file
51
packages/cli/src/databases/mysqldb/ExecutionEntity.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import {
|
||||
WorkflowExecuteMode,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
IExecutionFlattedDb,
|
||||
IWorkflowDb,
|
||||
} from '../../';
|
||||
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
Index,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
|
||||
@Entity()
|
||||
export class ExecutionEntity implements IExecutionFlattedDb {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column('text')
|
||||
data: string;
|
||||
|
||||
@Column()
|
||||
finished: boolean;
|
||||
|
||||
@Column('varchar')
|
||||
mode: WorkflowExecuteMode;
|
||||
|
||||
@Column({ nullable: true })
|
||||
retryOf: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
retrySuccessId: string;
|
||||
|
||||
@Column('timestamp')
|
||||
startedAt: Date;
|
||||
|
||||
@Column('timestamp')
|
||||
stoppedAt: Date;
|
||||
|
||||
@Column('json')
|
||||
workflowData: IWorkflowDb;
|
||||
|
||||
@Index()
|
||||
@Column({ nullable: true })
|
||||
workflowId: string;
|
||||
}
|
55
packages/cli/src/databases/mysqldb/WorkflowEntity.ts
Normal file
55
packages/cli/src/databases/mysqldb/WorkflowEntity.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import {
|
||||
IConnections,
|
||||
IDataObject,
|
||||
INode,
|
||||
IWorkflowSettings,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
IWorkflowDb,
|
||||
} from '../../';
|
||||
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
@Entity()
|
||||
export class WorkflowEntity implements IWorkflowDb {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({
|
||||
length: 128
|
||||
})
|
||||
name: string;
|
||||
|
||||
@Column()
|
||||
active: boolean;
|
||||
|
||||
@Column('json')
|
||||
nodes: INode[];
|
||||
|
||||
@Column('json')
|
||||
connections: IConnections;
|
||||
|
||||
@Column('timestamp')
|
||||
createdAt: Date;
|
||||
|
||||
@Column('timestamp')
|
||||
updatedAt: Date;
|
||||
|
||||
@Column({
|
||||
type: 'json',
|
||||
nullable: true,
|
||||
})
|
||||
settings?: IWorkflowSettings;
|
||||
|
||||
@Column({
|
||||
type: 'json',
|
||||
nullable: true,
|
||||
})
|
||||
staticData?: IDataObject;
|
||||
}
|
3
packages/cli/src/databases/mysqldb/index.ts
Normal file
3
packages/cli/src/databases/mysqldb/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './CredentialsEntity';
|
||||
export * from './ExecutionEntity';
|
||||
export * from './WorkflowEntity';
|
@ -17,7 +17,7 @@
|
||||
"build": "vue-cli-service build",
|
||||
"dev": "npm run serve",
|
||||
"lint": "vue-cli-service lint",
|
||||
"serve": "VUE_APP_URL_BASE_API=http://localhost:5678/ vue-cli-service serve",
|
||||
"serve": "cross-env VUE_APP_URL_BASE_API=http://localhost:5678/ vue-cli-service serve",
|
||||
"test": "npm run test:unit",
|
||||
"tslint": "tslint -p tsconfig.json -c tslint.json",
|
||||
"test:e2e": "vue-cli-service test:e2e",
|
||||
|
Loading…
Reference in New Issue
Block a user