// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using System.IO;
using System.Linq;
using EnsureThat;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.SqlServer.TransactSql.ScriptDom;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
namespace Microsoft.Health.Extensions.BuildTimeCodeGenerator.Sql;
///
/// Base class for generating C# types based on the CREATE TABLE, CREATE TABLE TYPE, CREATE PROCEDURE AND CREATE OR ALTER PROCEDURE statements in one or more .sql files.
///
public abstract class SqlModelGenerator : ICodeGenerator
{
private readonly string[] _sqlFiles;
protected SqlModelGenerator(string[] args)
{
EnsureArg.IsNotNull(args, nameof(args));
_sqlFiles = args;
}
protected abstract SqlVisitor[] Visitors { get; }
public (MemberDeclarationSyntax[], UsingDirectiveSyntax[]) Generate(string typeName)
{
IEnumerable sqlFragments = ParseSqlFiles();
var visitors = Visitors;
foreach (TSqlFragment sqlFragment in sqlFragments)
{
foreach (var sqlVisitor in visitors)
{
sqlFragment.Accept(sqlVisitor);
}
}
MemberDeclarationSyntax[] members = visitors
.SelectMany(v => v.MembersToAdd)
.OrderBy(m => m, MemberSorting.Comparer)
.ToArray();
return (
WrapMembers(members, typeName),
new[]
{
UsingDirective(ParseName("Microsoft.Health.SqlServer.Features.Client")),
UsingDirective(ParseName("Microsoft.Health.SqlServer.Features.Schema.Model")),
});
}
protected abstract MemberDeclarationSyntax[] WrapMembers(MemberDeclarationSyntax[] members, string containingTypeName);
private IEnumerable ParseSqlFiles()
{
foreach (var sqlFile in _sqlFiles)
{
using (var stream = File.OpenRead(sqlFile))
using (var reader = new StreamReader(stream))
{
var parser = new TSql150Parser(true);
yield return parser.Parse(reader, out var errors);
}
}
}
}