This repository has been archived by the owner on Aug 13, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5ae55ee
commit 0c241b7
Showing
25 changed files
with
651 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
CREATE TABLE `Person` ( | ||
Id int not null auto_increment primary key, | ||
Name nvarchar(255) not null, | ||
Title varchar(10), | ||
Age int, | ||
Price decimal(18, 2), | ||
DoB date, | ||
Deleted bit(1) not null default(0), | ||
PriceIncVat decimal(18, 2) AS (`Price` * 1.2) | ||
); |
45 changes: 45 additions & 0 deletions
45
TestScenarios/Read_AllColumnTypes/ExpectedOutput.MySql.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
{ | ||
"tables": { | ||
"`Person`": { | ||
"columns": { | ||
"Id": { | ||
"type": "int", | ||
"nullable": false, | ||
"primaryKey": true | ||
}, | ||
"Name": { | ||
"type": "nvarchar(255)", | ||
"nullable": false, | ||
"primaryKey": false | ||
}, | ||
"Title": { | ||
"type": "varchar(10)", | ||
"primaryKey": false | ||
}, | ||
"Age": { | ||
"type": "int", | ||
"primaryKey": false | ||
}, | ||
"Price": { | ||
"type": "decimal(18,2)", | ||
"primaryKey": false | ||
}, | ||
"DoB": { | ||
"type": "date", | ||
"primaryKey": false | ||
}, | ||
"Deleted": { | ||
"type": "bit(1)", | ||
"nullable": false, | ||
"default": 0, | ||
"primaryKey": false | ||
}, | ||
"PriceIncVat": { | ||
"expression": "`Price` * 1.2", | ||
"primaryKey": false, | ||
"type": "decimal(18,2)" | ||
} | ||
} | ||
} | ||
} | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
vcdb.MySql/SchemaBuilding/IMySqlComputedColumnRepository.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using System.Collections.Generic; | ||
using System.Data.Common; | ||
using System.Threading.Tasks; | ||
|
||
namespace vcdb.MySql.SchemaBuilding | ||
{ | ||
public interface IMySqlComputedColumnRepository | ||
{ | ||
Task<Dictionary<string, string>> GetComputedColumns(DbConnection connection, ObjectName tableName); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
namespace vcdb.MySql.SchemaBuilding.Models | ||
{ | ||
public class ComputedColumn | ||
{ | ||
public string TABLE_SCHEMA { get; set; } | ||
public string TABLE_NAME { get; set; } | ||
public string COLUMN_NAME { get; set; } | ||
public string GENERATION_EXPRESSION { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
namespace vcdb.MySql.SchemaBuilding.Models | ||
{ | ||
public class DescribeOutput | ||
{ | ||
public string Field { get; set; } | ||
public string Type { get; set; } | ||
public string Null { get; set; } | ||
public string Key { get; set; } | ||
public string Default { get; set; } | ||
public string Extra { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace vcdb.MySql.SchemaBuilding.Models | ||
{ | ||
public class TableCollation | ||
{ | ||
public string column_name { get; set; } | ||
public string charset_name { get; set; } | ||
public string collation_name { get; set; } | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
vcdb.MySql/SchemaBuilding/MySqlCheckConstraintRepository.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using System.Collections.Generic; | ||
using System.Data.Common; | ||
using System.Threading.Tasks; | ||
using vcdb.Models; | ||
using vcdb.SchemaBuilding; | ||
|
||
namespace vcdb.MySql.SchemaBuilding | ||
{ | ||
public class MySqlCheckConstraintRepository : ICheckConstraintRepository | ||
{ | ||
public Task<IEnumerable<CheckConstraintDetails>> GetCheckConstraints(DbConnection connection, ObjectName tableName) | ||
{ | ||
return Task.FromResult<IEnumerable<CheckConstraintDetails>>(new CheckConstraintDetails[0]); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
using Dapper; | ||
using System.Collections.Generic; | ||
using System.Data.Common; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using vcdb.MySql.SchemaBuilding.Models; | ||
using vcdb.SchemaBuilding; | ||
|
||
namespace vcdb.MySql.SchemaBuilding | ||
{ | ||
public class MySqlCollationRepository : ICollationRepository | ||
{ | ||
public async Task<Dictionary<string, string>> GetColumnCollations(DbConnection connection, ObjectName tableName) | ||
{ | ||
var columns = await connection.QueryAsync<TableCollation>(@"SELECT | ||
column_name, | ||
character_set_name, | ||
collation_name | ||
FROM information_schema.columns | ||
WHERE table_name = @table_name;", | ||
new { table_name = tableName.Name, schema = tableName.Schema }); | ||
|
||
return columns.ToDictionary( | ||
column => column.column_name, | ||
column => column.collation_name); | ||
} | ||
|
||
public async Task<string> GetDatabaseCollation(DbConnection connection) | ||
{ | ||
var databaseCollation = await connection.QuerySingleAsync<string>("SHOW VARIABLES LIKE 'collation_database';"); | ||
if (databaseCollation == "collation_database") | ||
{ | ||
return await GetServerCollation(connection); | ||
} | ||
|
||
return databaseCollation; | ||
} | ||
|
||
public async Task<string> GetServerCollation(DbConnection connection) | ||
{ | ||
return await connection.QuerySingleAsync<string>("SELECT @@collation_server;"); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
using Dapper; | ||
using System.Collections.Generic; | ||
using System.Data.Common; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using vcdb.Models; | ||
using vcdb.MySql.SchemaBuilding.Models; | ||
using vcdb.SchemaBuilding; | ||
|
||
namespace vcdb.MySql.SchemaBuilding | ||
{ | ||
public class MySqlColumnRepository : IColumnRepository | ||
{ | ||
/// <summary> | ||
/// From this page: https://bugs.mysql.com/bug.php?id=69620 | ||
/// | ||
/// "nvarchar in MySQL is just an alias for VARCHAR and CHARACTER SET utf8. If you set the default charset in your DB and/or tables to utf8 you should be fine with VARCHAR in your columns" | ||
/// | ||
/// This is the name of the utf8 collation, if it is set, then consider any varchar() or char() columns to be nvarchar() or nchar() instead | ||
/// </summary> | ||
private const string Utf8Collation = "utf8_general_ci"; | ||
|
||
private readonly IDescriptionRepository descriptionRepository; | ||
private readonly ICollationRepository collationRepository; | ||
private readonly IPrimaryKeyRepository primaryKeyRepository; | ||
|
||
private readonly IMySqlComputedColumnRepository computedColumnRepository; | ||
|
||
public MySqlColumnRepository( | ||
IDescriptionRepository descriptionRepository, | ||
ICollationRepository collationRepository, | ||
IPrimaryKeyRepository primaryKeyRepository, | ||
IMySqlComputedColumnRepository computedColumnRepository) | ||
{ | ||
this.descriptionRepository = descriptionRepository; | ||
this.collationRepository = collationRepository; | ||
this.primaryKeyRepository = primaryKeyRepository; | ||
this.computedColumnRepository = computedColumnRepository; | ||
} | ||
|
||
public async Task<Dictionary<string, ColumnDetails>> GetColumns(DbConnection connection, ObjectName tableName, Permissions tablePermissions) | ||
{ | ||
var databaseCollation = await collationRepository.GetDatabaseCollation(connection); | ||
var columnDescriptions = await descriptionRepository.GetColumnDescriptions(connection, tableName); | ||
var columnCollations = await collationRepository.GetColumnCollations(connection, tableName); | ||
var columnsInPrimaryKey = await primaryKeyRepository.GetColumnsInPrimaryKey(connection, tableName); | ||
var computedColumns = await computedColumnRepository.GetComputedColumns(connection, tableName); | ||
|
||
return await connection.QueryAsync<DescribeOutput>($@" | ||
describe {tableName.Name}").ToDictionaryAsync( | ||
column => column.Field, | ||
column => | ||
{ | ||
return new ColumnDetails | ||
{ | ||
Type = NormaliseDataType(column, columnCollations), | ||
Nullable = OptOut.From(column.Null == "YES"), | ||
Default = UnwrapDefinition(column.Default), | ||
/*DefaultName = columnDefault == null || columnDefault.IsSystemNamed | ||
? null | ||
: columnDefault.Name, | ||
SqlDefaultName = columnDefault?.Name, | ||
DefaultObjectId = columnDefault?.ObjectId,*/ | ||
Description = columnDescriptions.ItemOrDefault(column.Field), | ||
Collation = columnCollations.ItemOrDefault(column.Field) == databaseCollation || IsNationalCharacterColumn(column, columnCollations) | ||
? null | ||
: columnCollations.ItemOrDefault(column.Field), | ||
PrimaryKey = columnsInPrimaryKey.Contains(column.Field), | ||
Permissions = tablePermissions?.SubEntityPermissions?.ItemOrDefault(column.Field), | ||
Expression = computedColumns.ItemOrDefault(column.Field) | ||
}; | ||
}); | ||
} | ||
|
||
private bool IsNationalCharacterColumn(DescribeOutput column, Dictionary<string, string> columnCollations) | ||
{ | ||
var columnCollation = columnCollations.ItemOrDefault(column.Field); | ||
var isUtf8Collation = columnCollation == Utf8Collation; | ||
return (column.Type.StartsWith("varchar(") || column.Type.StartsWith("char(")) && isUtf8Collation; | ||
} | ||
|
||
private string NormaliseDataType(DescribeOutput column, Dictionary<string, string> columnCollations) | ||
{ | ||
if (IsNationalCharacterColumn(column, columnCollations)) | ||
{ | ||
return "n" + column.Type; | ||
} | ||
|
||
return column.Type; | ||
} | ||
|
||
private object UnwrapDefinition(object definition) | ||
{ | ||
if (definition is string stringDefinition) | ||
{ | ||
if (string.IsNullOrEmpty(stringDefinition)) | ||
return definition; | ||
|
||
if (stringDefinition.StartsWith("\"") && stringDefinition.EndsWith("\"")) | ||
return stringDefinition.Trim('\"'); | ||
|
||
if (int.TryParse(stringDefinition, out var intValue)) | ||
return intValue; | ||
|
||
if (decimal.TryParse(stringDefinition, out var decimalValue)) | ||
return decimalValue; | ||
} | ||
|
||
return definition; | ||
} | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
vcdb.MySql/SchemaBuilding/MySqlComputedColumnRepository.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using Dapper; | ||
using System.Collections.Generic; | ||
using System.Data.Common; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using vcdb.MySql.SchemaBuilding.Models; | ||
|
||
namespace vcdb.MySql.SchemaBuilding | ||
{ | ||
public class MySqlComputedColumnRepository : IMySqlComputedColumnRepository | ||
{ | ||
public async Task<Dictionary<string, string>> GetComputedColumns(DbConnection connection, ObjectName tableName) | ||
{ | ||
var computedColums = await connection.QueryAsync<ComputedColumn>(@"select TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, GENERATION_EXPRESSION | ||
from INFORMATION_SCHEMA.COLUMNS | ||
where TABLE_SCHEMA = DATABASE() | ||
and TABLE_NAME = @tableName | ||
and GENERATION_EXPRESSION <> ''", new { tableName = tableName.Name }); | ||
|
||
return computedColums.ToDictionary( | ||
col => col.COLUMN_NAME, | ||
col => col.GENERATION_EXPRESSION.UnwrapDefinition()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
using System.Data.Common; | ||
using System.Threading.Tasks; | ||
using vcdb.Models; | ||
using vcdb.SchemaBuilding; | ||
|
||
namespace vcdb.MySql.SchemaBuilding | ||
{ | ||
public class MySqlDatabaseRepository : IDatabaseRepository | ||
{ | ||
private readonly ITableRepository tableRepository; | ||
private readonly ISchemaRepository schemaRepository; | ||
private readonly IDescriptionRepository descriptionRepository; | ||
private readonly ICollationRepository collationRepository; | ||
private readonly IUserRepository userRepository; | ||
private readonly IPermissionRepository permissionRepository; | ||
private readonly IProcedureRepository procedureRepository; | ||
|
||
public MySqlDatabaseRepository( | ||
ITableRepository tableRepository, | ||
ISchemaRepository schemaRepository, | ||
IDescriptionRepository descriptionRepository, | ||
ICollationRepository collationRepository, | ||
IUserRepository userRepository, | ||
IPermissionRepository permissionRepository, | ||
IProcedureRepository procedureRepository) | ||
{ | ||
this.tableRepository = tableRepository; | ||
this.schemaRepository = schemaRepository; | ||
this.descriptionRepository = descriptionRepository; | ||
this.collationRepository = collationRepository; | ||
this.userRepository = userRepository; | ||
this.permissionRepository = permissionRepository; | ||
this.procedureRepository = procedureRepository; | ||
} | ||
|
||
public async Task<DatabaseDetails> GetDatabaseDetails(DbConnection connection) | ||
{ | ||
var serverCollation = await collationRepository.GetServerCollation(connection); | ||
var databaseCollation = await collationRepository.GetDatabaseCollation(connection); | ||
|
||
return new DatabaseDetails | ||
{ | ||
Tables = await tableRepository.GetTables(connection), | ||
Schemas = await schemaRepository.GetSchemas(connection), | ||
Description = await descriptionRepository.GetDatabaseDescription(connection), | ||
Collation = databaseCollation == serverCollation | ||
? null | ||
: databaseCollation, | ||
ServerCollation = serverCollation, | ||
Users = await userRepository.GetUsers(connection), | ||
Permissions = await permissionRepository.GetDatabasePermissions(connection), | ||
Procedures = await procedureRepository.GetProcedures(connection) | ||
}; | ||
} | ||
} | ||
} |
Oops, something went wrong.