mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08: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
|
_START_PACKAGE
|
||||||
.env
|
.env
|
||||||
.vscode
|
.vscode
|
||||||
|
.idea
|
||||||
|
|
|
@ -8,7 +8,7 @@ const config = convict({
|
||||||
database: {
|
database: {
|
||||||
type: {
|
type: {
|
||||||
doc: 'Type of database to use',
|
doc: 'Type of database to use',
|
||||||
format: ['sqlite', 'mongodb', 'postgresdb'],
|
format: ['sqlite', 'mongodb', 'mysqldb', 'postgresdb'],
|
||||||
default: 'sqlite',
|
default: 'sqlite',
|
||||||
env: 'DB_TYPE'
|
env: 'DB_TYPE'
|
||||||
},
|
},
|
||||||
|
@ -52,6 +52,38 @@ const config = convict({
|
||||||
env: 'DB_POSTGRESDB_USER'
|
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: {
|
executions: {
|
||||||
|
|
|
@ -18,6 +18,7 @@ import {
|
||||||
MongoDb,
|
MongoDb,
|
||||||
PostgresDb,
|
PostgresDb,
|
||||||
SQLite,
|
SQLite,
|
||||||
|
MySQLDb,
|
||||||
} from './databases';
|
} from './databases';
|
||||||
|
|
||||||
export let collections: IDatabaseCollections = {
|
export let collections: IDatabaseCollections = {
|
||||||
|
@ -36,14 +37,17 @@ export async function init(synchronize?: boolean): Promise<IDatabaseCollections>
|
||||||
let connectionOptions: ConnectionOptions;
|
let connectionOptions: ConnectionOptions;
|
||||||
|
|
||||||
let dbNotExistError: string | undefined;
|
let dbNotExistError: string | undefined;
|
||||||
if (dbType === 'mongodb') {
|
switch (dbType) {
|
||||||
|
case 'mongodb':
|
||||||
entities = MongoDb;
|
entities = MongoDb;
|
||||||
connectionOptions = {
|
connectionOptions = {
|
||||||
type: 'mongodb',
|
type: 'mongodb',
|
||||||
url: await GenericHelpers.getConfigValue('database.mongodb.connectionUrl') as string,
|
url: await GenericHelpers.getConfigValue('database.mongodb.connectionUrl') as string,
|
||||||
useNewUrlParser: true,
|
useNewUrlParser: true,
|
||||||
};
|
};
|
||||||
} else if (dbType === 'postgresdb') {
|
break;
|
||||||
|
|
||||||
|
case 'postgresdb':
|
||||||
dbNotExistError = 'does not exist';
|
dbNotExistError = 'does not exist';
|
||||||
entities = PostgresDb;
|
entities = PostgresDb;
|
||||||
connectionOptions = {
|
connectionOptions = {
|
||||||
|
@ -54,14 +58,31 @@ export async function init(synchronize?: boolean): Promise<IDatabaseCollections>
|
||||||
port: await GenericHelpers.getConfigValue('database.postgresdb.port') as number,
|
port: await GenericHelpers.getConfigValue('database.postgresdb.port') as number,
|
||||||
username: await GenericHelpers.getConfigValue('database.postgresdb.user') as string,
|
username: await GenericHelpers.getConfigValue('database.postgresdb.user') as string,
|
||||||
};
|
};
|
||||||
} else if (dbType === 'sqlite') {
|
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:';
|
dbNotExistError = 'no such table:';
|
||||||
entities = SQLite;
|
entities = SQLite;
|
||||||
connectionOptions = {
|
connectionOptions = {
|
||||||
type: 'sqlite',
|
type: 'sqlite',
|
||||||
database: path.join(n8nFolder, 'database.sqlite'),
|
database: path.join(n8nFolder, 'database.sqlite'),
|
||||||
};
|
};
|
||||||
} else {
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
throw new Error(`The database "${dbType}" is currently not supported!`);
|
throw new Error(`The database "${dbType}" is currently not supported!`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ export interface ICredentialsDecryptedResponse extends ICredentialsDecryptedDb {
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DatabaseType = 'mongodb' | 'postgresdb' | 'sqlite';
|
export type DatabaseType = 'mongodb' | 'postgresdb' | 'mysqldb' | 'sqlite';
|
||||||
export type SaveExecutionDataType = 'all' | 'none';
|
export type SaveExecutionDataType = 'all' | 'none';
|
||||||
|
|
||||||
export interface IExecutionBase {
|
export interface IExecutionBase {
|
||||||
|
|
|
@ -208,9 +208,17 @@ export class TestWebhooks {
|
||||||
}
|
}
|
||||||
const nodeTypes = NodeTypes();
|
const nodeTypes = NodeTypes();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 = {
|
const findQuery = {
|
||||||
where: {
|
where: {
|
||||||
id: findIn(this.activeWebhooks.getWorkflowIds())
|
id: findIn(WorkflowIds)
|
||||||
},
|
},
|
||||||
} as FindManyOptions;
|
} as FindManyOptions;
|
||||||
|
|
||||||
|
@ -223,11 +231,9 @@ export class TestWebhooks {
|
||||||
|
|
||||||
return this.activeWebhooks.removeAll(workflows);
|
return this.activeWebhooks.removeAll(workflows);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let testWebhooksInstance: TestWebhooks | undefined;
|
let testWebhooksInstance: TestWebhooks | undefined;
|
||||||
|
|
||||||
export function getInstance(): TestWebhooks {
|
export function getInstance(): TestWebhooks {
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import * as MongoDb from './mongodb';
|
import * as MongoDb from './mongodb';
|
||||||
import * as PostgresDb from './postgresdb';
|
import * as PostgresDb from './postgresdb';
|
||||||
import * as SQLite from './sqlite';
|
import * as SQLite from './sqlite';
|
||||||
|
import * as MySQLDb from './mysqldb';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
MongoDb,
|
MongoDb,
|
||||||
PostgresDb,
|
PostgresDb,
|
||||||
SQLite,
|
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",
|
"build": "vue-cli-service build",
|
||||||
"dev": "npm run serve",
|
"dev": "npm run serve",
|
||||||
"lint": "vue-cli-service lint",
|
"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",
|
"test": "npm run test:unit",
|
||||||
"tslint": "tslint -p tsconfig.json -c tslint.json",
|
"tslint": "tslint -p tsconfig.json -c tslint.json",
|
||||||
"test:e2e": "vue-cli-service test:e2e",
|
"test:e2e": "vue-cli-service test:e2e",
|
||||||
|
|
Loading…
Reference in a new issue