Skip to content

Commit

Permalink
Add PK & FKs to the table model
Browse files Browse the repository at this point in the history
FKs is not fully functional.
Blocked by #15
  • Loading branch information
Bardin08 committed Apr 16, 2024
1 parent 8a1b2e2 commit 070520a
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 10 deletions.
7 changes: 7 additions & 0 deletions DbSeeder/Schema/ForeignKey.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace DbSeeder.Schema;

public record ForeignKey(
Table Table,
Column Column,
Table RefTable,
Column RefColumn);
5 changes: 5 additions & 0 deletions DbSeeder/Schema/PrimaryKey.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace DbSeeder.Schema;

public record PrimaryKey(
Table Table,
Column Column);
8 changes: 5 additions & 3 deletions DbSeeder/Schema/SqlSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
public class SqlSchema
{
private readonly List<Table> _tables = [];

public IReadOnlyList<Table> Tables => _tables;

public void AddTable(Table table)
{
_tables.Add(table);
}
=> _tables.Add(table);

public Table? GetTableByName(string tableName)
=> _tables.FirstOrDefault(t => t.Name.Equals(tableName, StringComparison.OrdinalIgnoreCase));

Check warning on line 13 in DbSeeder/Schema/SqlSchema.cs

View workflow job for this annotation

GitHub Actions / main

"Find" method should be used instead of the "FirstOrDefault" extension method. (https://rules.sonarsource.com/csharp/RSPEC-6602)
}
8 changes: 3 additions & 5 deletions DbSeeder/Schema/SqlSchemaBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,21 +54,19 @@ private void TraverseCreateStatement(SyntaxTreeNode createStatementNode)
private Table CreateTable(SyntaxTreeNode tableRoot)
{
var tableName = tableRoot.Value;
var table = new Table(tableName);
var table = new Table(tableName, _sqlSchema!);

// Actually, now we expect that table root contains only cols, but in the future more sub-nodes can be added,
// so we have to be sure that we're working exactly with a node that contains cols.
var colsRoot = tableRoot.Children.First(x => x?.Type is SyntaxTreeNodeType.TableColumns);
var cols = ParseColumns(colsRoot!);
table.Columns.AddRange(cols);
table.AddColumns(cols);

return table;
}

private IEnumerable<Column> ParseColumns(SyntaxTreeNode colsRoot)
{
return colsRoot.Children.Select(GetColumn!).ToList();
}
=> colsRoot.Children.Select(GetColumn!).ToList();

private Column GetColumn(SyntaxTreeNode columnNode)
{
Expand Down
71 changes: 69 additions & 2 deletions DbSeeder/Schema/Table.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,74 @@
namespace DbSeeder.Schema;

public class Table(string name)
public class Table(string name, SqlSchema schema)
{
private readonly List<Column> _columns = [];
private readonly List<ForeignKey> _foreignKeys = [];

// There are some rules how to deal if PK is not defined
// ex: find the first attribute with NOT NULL & UNIQUE constraints
public PrimaryKey? PrimaryKey { get; private set; }
public string Name { get; } = name;
public List<Column> Columns { get; } = [];
public IReadOnlyList<Column> Columns => _columns;
public IReadOnlyList<ForeignKey> ForeignKeys => _foreignKeys;

public void AddColumns(IEnumerable<Column> columns)
{
foreach (var column in columns)
{
AddColumn(column);
}
}

private void AddColumn(Column column)
{
ArgumentNullException.ThrowIfNull(column);
_columns.Add(column);

if (column.IsPrimaryKey)
{
SetTablePrimaryKey(column);
}
else if (column.IsForeignKey)
{
SetTableForeignKey(column);
}
}

private void SetTablePrimaryKey(Column column)
{
if (PrimaryKey != null)
{
throw new ArgumentException("Table can not contains more that one PRIMARY KEY");
}

PrimaryKey = new PrimaryKey(this, column);
}

private void SetTableForeignKey(Column column)
{
ArgumentNullException.ThrowIfNull(column.ForeignKeyRef);

var refTable = schema.GetTableByName(column.ForeignKeyRef.TableName);
if (refTable is null)
{
throw new InvalidOperationException($"Referenced table {column.ForeignKeyRef.TableName} is not exists " +
$"in current schema. Validate the order of the create statements, " +
$"it's matter");
}

var refColumn = refTable.GetColumnByName(column.ForeignKeyRef.ColumnName);
if (refColumn is null)
{
throw new InvalidOperationException($"Referenced table {column.ForeignKeyRef.TableName} is not exists " +
$"in current schema. Validate the order of the create statements, " +
$"it's matter");
}

var fk = new ForeignKey(this, column, refTable, refColumn);
_foreignKeys.Add(fk);
}

private Column? GetColumnByName(string columnName)
=> Columns.FirstOrDefault(c => c.Name.Equals(columnName, StringComparison.Ordinal));
}

0 comments on commit 070520a

Please sign in to comment.