Skip to content

Commit

Permalink
Merge pull request #247 from SimonNyvall/feat/mysql-connection
Browse files Browse the repository at this point in the history
Add MySQL Database Connection Support
  • Loading branch information
tareqimbasher authored Aug 18, 2024
2 parents 4c90dea + 6ebbbfd commit 679f61c
Show file tree
Hide file tree
Showing 15 changed files with 353 additions and 5 deletions.
61 changes: 60 additions & 1 deletion src/Apps/NetPad.Apps.App/App/src/core/@application/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3530,6 +3530,11 @@ export abstract class DataConnection implements IDataConnection {
result.init(data);
return result;
}
if (data["discriminator"] === "MySqlDatabaseConnection") {
let result = new MySqlDatabaseConnection();
result.init(data);
return result;
}
throw new Error("The abstract class 'DataConnection' cannot be instantiated.");
}

Expand All @@ -3553,7 +3558,7 @@ export interface IDataConnection {
type: DataConnectionType;
}

export type DataConnectionType = "MSSQLServer" | "PostgreSQL" | "SQLite";
export type DataConnectionType = "MSSQLServer" | "PostgreSQL" | "SQLite" | "MySQL";

export class DataConnectionTestResult implements IDataConnectionTestResult {
success!: boolean;
Expand Down Expand Up @@ -5376,6 +5381,7 @@ export class Types implements ITypes {
msSqlServerDatabaseConnection?: MsSqlServerDatabaseConnection | undefined;
postgreSqlDatabaseConnection?: PostgreSqlDatabaseConnection | undefined;
sqLiteDatabaseConnection?: SQLiteDatabaseConnection | undefined;
mySqlDatabaseConnection?: MySqlDatabaseConnection | undefined;

constructor(data?: ITypes) {
if (data) {
Expand Down Expand Up @@ -5424,6 +5430,7 @@ export class Types implements ITypes {
this.msSqlServerDatabaseConnection = _data["msSqlServerDatabaseConnection"] ? MsSqlServerDatabaseConnection.fromJS(_data["msSqlServerDatabaseConnection"]) : <any>undefined;
this.postgreSqlDatabaseConnection = _data["postgreSqlDatabaseConnection"] ? PostgreSqlDatabaseConnection.fromJS(_data["postgreSqlDatabaseConnection"]) : <any>undefined;
this.sqLiteDatabaseConnection = _data["sqLiteDatabaseConnection"] ? SQLiteDatabaseConnection.fromJS(_data["sqLiteDatabaseConnection"]) : <any>undefined;
this.mySqlDatabaseConnection = _data["mySqlDatabaseConnection"] ? MySqlDatabaseConnection.fromJS(_data["mySqlDatabaseConnection"]) : <any>undefined;
}
}

Expand Down Expand Up @@ -5472,6 +5479,7 @@ export class Types implements ITypes {
data["msSqlServerDatabaseConnection"] = this.msSqlServerDatabaseConnection ? this.msSqlServerDatabaseConnection.toJSON() : <any>undefined;
data["postgreSqlDatabaseConnection"] = this.postgreSqlDatabaseConnection ? this.postgreSqlDatabaseConnection.toJSON() : <any>undefined;
data["sqLiteDatabaseConnection"] = this.sqLiteDatabaseConnection ? this.sqLiteDatabaseConnection.toJSON() : <any>undefined;
data["mySqlDatabaseConnection"] = this.mySqlDatabaseConnection ? this.mySqlDatabaseConnection.toJSON() : <any>undefined;
return data;
}

Expand Down Expand Up @@ -5520,6 +5528,7 @@ export interface ITypes {
msSqlServerDatabaseConnection?: MsSqlServerDatabaseConnection | undefined;
postgreSqlDatabaseConnection?: PostgreSqlDatabaseConnection | undefined;
sqLiteDatabaseConnection?: SQLiteDatabaseConnection | undefined;
mySqlDatabaseConnection?: MySqlDatabaseConnection | undefined;
}

export type YesNoCancel = "Yes" | "No" | "Cancel";
Expand Down Expand Up @@ -7380,6 +7389,11 @@ export abstract class DatabaseConnection extends DataConnection implements IData
result.init(data);
return result;
}
if (data["discriminator"] === "MySqlDatabaseConnection") {
let result = new MySqlDatabaseConnection();
result.init(data);
return result;
}
throw new Error("The abstract class 'DatabaseConnection' cannot be instantiated.");
}

Expand Down Expand Up @@ -7448,6 +7462,11 @@ export abstract class EntityFrameworkDatabaseConnection extends DatabaseConnecti
result.init(data);
return result;
}
if (data["discriminator"] === "MySqlDatabaseConnection") {
let result = new MySqlDatabaseConnection();
result.init(data);
return result;
}
throw new Error("The abstract class 'EntityFrameworkDatabaseConnection' cannot be instantiated.");
}

Expand Down Expand Up @@ -7497,6 +7516,11 @@ export abstract class EntityFrameworkRelationalDatabaseConnection extends Entity
result.init(data);
return result;
}
if (data["discriminator"] === "MySqlDatabaseConnection") {
let result = new MySqlDatabaseConnection();
result.init(data);
return result;
}
throw new Error("The abstract class 'EntityFrameworkRelationalDatabaseConnection' cannot be instantiated.");
}

Expand Down Expand Up @@ -7663,6 +7687,41 @@ export class PostgreSqlDatabaseConnection extends EntityFrameworkRelationalDatab
export interface IPostgreSqlDatabaseConnection extends IEntityFrameworkRelationalDatabaseConnection {
}

export class MySqlDatabaseConnection extends EntityFrameworkRelationalDatabaseConnection implements IMySqlDatabaseConnection {

constructor(data?: IMySqlDatabaseConnection) {
super(data);
this._discriminator = "MySqlDatabaseConnection";
}

init(_data?: any) {
super.init(_data);
}

static fromJS(data: any): MySqlDatabaseConnection {
data = typeof data === 'object' ? data : {};
let result = new MySqlDatabaseConnection();
result.init(data);
return result;
}

toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
super.toJSON(data);
return data;
}

clone(): MySqlDatabaseConnection {
const json = this.toJSON();
let result = new MySqlDatabaseConnection();
result.init(json);
return result;
}
}

export interface IMySqlDatabaseConnection extends IEntityFrameworkRelationalDatabaseConnection {
}

export class SQLiteDatabaseConnection extends EntityFrameworkRelationalDatabaseConnection implements ISQLiteDatabaseConnection {

constructor(data?: ISQLiteDatabaseConnection) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export class DataConnectionName {
return "/img/postgresql2.png";
case "SQLite":
return "/img/sqlite.png";
case "MySQL":
return "/img/mysql.png";
default:
return "";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {
DataConnection,
MsSqlServerDatabaseConnection,
PostgreSqlDatabaseConnection,
SQLiteDatabaseConnection
SQLiteDatabaseConnection,
MySqlDatabaseConnection
} from "@application";
import {IDataConnectionView} from "./idata-connection-view";
import {IDataConnectionViewComponent} from "./components/idata-connection-view-component";
Expand Down Expand Up @@ -57,6 +58,8 @@ export abstract class DataConnectionView<TDataConnection extends DataConnection>
connection.type = "PostgreSQL";
} else if (ctor.name === SQLiteDatabaseConnection.name) {
connection.type = "SQLite";
} else if (ctor.name === MySqlDatabaseConnection.name) {
connection.type = "MySQL";
} else {
throw new Error("Unhandled data connection type: " + ctor.name);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<au-compose repeat.for="component of components"
component.bind="component"></au-compose>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {DataConnection, IDataConnectionService, MySqlDatabaseConnection,} from "@application";
import {HostAndPortComponent} from "../components/host-and-port-component";
import {AuthComponent} from "../components/auth-component";
import {DatabaseComponent} from "../components/database-component";
import {DataConnectionView} from "../data-connection-view";

export class MysqlView extends DataConnectionView<MySqlDatabaseConnection> {
constructor(connection: DataConnection | undefined, dataConnectionService: IDataConnectionService) {
super(MySqlDatabaseConnection, connection);

this.components = [
new HostAndPortComponent(this.connection),
new AuthComponent(this.connection, dataConnectionService),
new DatabaseComponent(
this.connection,
undefined,
{
enabled: true,
requirementsToLoadAreMet: () => this.components.slice(0, 2).every(c => !c.validationError),
dataConnectionService: dataConnectionService
}
)
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {IDataConnectionView} from "./connection-views/idata-connection-view";
import {MssqlView} from "./connection-views/mssql/mssql-view";
import {PostgresqlView} from "./connection-views/postgresql/postgresql-view";
import {SqliteView} from "./connection-views/sqlite/sqlite-view";
import {MysqlView} from "./connection-views/mysql/mysql-view";

export class Window extends WindowBase {
public connectionView?: IDataConnectionView;
Expand Down Expand Up @@ -36,6 +37,10 @@ export class Window extends WindowBase {
label: '<img src="/img/postgresql2.png" class="connection-type-logo"/> PostgreSQL',
type: "PostgreSQL"
},
{
label: '<img src="/img/mysql.png" class="connection-type-logo"/> MySQL',
type: "MySQL"
}
];

// Until we implement a way to add a SQLite file in the browser, this option will only be available in Electron app
Expand Down Expand Up @@ -152,6 +157,10 @@ export class Window extends WindowBase {
return new SqliteView(connection, this.dataConnectionService);
}

if (connectionType === "MySQL") {
return new MysqlView(connection, this.dataConnectionService);
}

return undefined;
}

Expand Down
1 change: 1 addition & 0 deletions src/Apps/NetPad.Apps.App/Controllers/TypesController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,6 @@ private class Types
public MsSqlServerDatabaseConnection? MsSqlServerDatabaseConnection { get; set; }
public PostgreSqlDatabaseConnection? PostgreSqlDatabaseConnection { get; set; }
public SQLiteDatabaseConnection? SQLiteDatabaseConnection { get; set; }
public MySqlDatabaseConnection? MySqlDatabaseConnection { get; set; }
}
}
Binary file added src/Apps/NetPad.Apps.App/wwwroot/img/mysql.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System.Data.Common;
using Microsoft.EntityFrameworkCore;
using NetPad.Apps.Data.EntityFrameworkCore.Scaffolding;
using NetPad.Data;

namespace NetPad.Apps.Data.EntityFrameworkCore.DataConnections;

public sealed class MySqlDatabaseConnection(Guid id, string name, ScaffoldOptions? scaffoldOptions = null)
: EntityFrameworkRelationalDatabaseConnection(id, name, DataConnectionType.MySQL,
"Pomelo.EntityFrameworkCore.MySql", scaffoldOptions)
{
public override string GetConnectionString(IDataConnectionPasswordProtector passwordProtector)
{
ConnectionStringBuilder connectionStringBuilder = [];

string host = Host ?? string.Empty;

if (!string.IsNullOrWhiteSpace(Port))
{
host += $";Port={Port}";
}

connectionStringBuilder.TryAdd("Server", host);
connectionStringBuilder.TryAdd("Database", DatabaseName);

if (UserId != null)
{
connectionStringBuilder.TryAdd("Uid", UserId);
}

if (Password != null)
{
connectionStringBuilder.TryAdd("Pwd", passwordProtector.Unprotect(Password));
}

if (!string.IsNullOrWhiteSpace(ConnectionStringAugment))
{
connectionStringBuilder.Augment(new ConnectionStringBuilder(ConnectionStringAugment));
}

return connectionStringBuilder.Build();
}

public override Task ConfigureDbContextOptionsAsync(DbContextOptionsBuilder builder, IDataConnectionPasswordProtector passwordProtector)
{
var connectionString = GetConnectionString(passwordProtector);

var serverVersion = MySqlServerVersion.AutoDetect(connectionString);

builder.UseMySql(connectionString, serverVersion, options =>
{
options.EnableRetryOnFailure();
});

return Task.CompletedTask;
}

public override async Task<IEnumerable<string>> GetDatabasesAsync(IDataConnectionPasswordProtector passwordProtector)
{
await using DatabaseContext context = CreateDbContext(passwordProtector);
await using DbCommand command = context.Database.GetDbConnection().CreateCommand();

command.CommandText = "select schema_name from information_schema.schemata;";
await context.Database.OpenConnectionAsync();

await using DbDataReader result = await command.ExecuteReaderAsync();

List<string> databases = [];

while (await result.ReadAsync())
{
databases.Add((string)result["schema_name"]);
}

return databases;
}
}
Loading

0 comments on commit 679f61c

Please sign in to comment.