diff --git a/DbSeeder/Schema/ForeignKey.cs b/DbSeeder/Schema/ForeignKey.cs
new file mode 100644
index 0000000..2b9728b
--- /dev/null
+++ b/DbSeeder/Schema/ForeignKey.cs
@@ -0,0 +1,7 @@
+namespace DbSeeder.Schema;
+
+public record ForeignKey(
+ Table Table,
+ Column Column,
+ Table RefTable,
+ Column RefColumn);
\ No newline at end of file
diff --git a/DbSeeder/Schema/PrimaryKey.cs b/DbSeeder/Schema/PrimaryKey.cs
new file mode 100644
index 0000000..9f27c86
--- /dev/null
+++ b/DbSeeder/Schema/PrimaryKey.cs
@@ -0,0 +1,5 @@
+namespace DbSeeder.Schema;
+
+public record PrimaryKey(
+ Table Table,
+ Column Column);
\ No newline at end of file
diff --git a/DbSeeder/Schema/SqlSchema.cs b/DbSeeder/Schema/SqlSchema.cs
index b2460ac..1ee0ba5 100644
--- a/DbSeeder/Schema/SqlSchema.cs
+++ b/DbSeeder/Schema/SqlSchema.cs
@@ -3,10 +3,12 @@
public class SqlSchema
{
private readonly List
_tables = [];
+
public IReadOnlyList 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));
}
diff --git a/DbSeeder/Schema/SqlSchemaBuilder.cs b/DbSeeder/Schema/SqlSchemaBuilder.cs
index 470c867..8ca0ec2 100644
--- a/DbSeeder/Schema/SqlSchemaBuilder.cs
+++ b/DbSeeder/Schema/SqlSchemaBuilder.cs
@@ -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 ParseColumns(SyntaxTreeNode colsRoot)
- {
- return colsRoot.Children.Select(GetColumn!).ToList();
- }
+ => colsRoot.Children.Select(GetColumn!).ToList();
private Column GetColumn(SyntaxTreeNode columnNode)
{
diff --git a/DbSeeder/Schema/Table.cs b/DbSeeder/Schema/Table.cs
index 06bbb06..3cded09 100644
--- a/DbSeeder/Schema/Table.cs
+++ b/DbSeeder/Schema/Table.cs
@@ -1,7 +1,74 @@
namespace DbSeeder.Schema;
-public class Table(string name)
+public class Table(string name, SqlSchema schema)
{
+ private readonly List _columns = [];
+ private readonly List _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 Columns { get; } = [];
+ public IReadOnlyList Columns => _columns;
+ public IReadOnlyList ForeignKeys => _foreignKeys;
+
+ public void AddColumns(IEnumerable 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));
}