読者です 読者をやめる 読者になる 読者になる

ScriptDom のデバッグ用 Visitor

クエリが SQL Database でサポートされているかを ScriptDom で判定する(作成中) - お だ のスペース を実装してるんですが、どの構文が何の TSqlFragment クラス (Microsoft.SqlServer.TransactSql.ScriptDom) を継承してるか分かりにくいのが難点です。

というわけで、確認用の Visitor を T4 で用意してみました。

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="C:\Program Files (x86)\Microsoft SQL Server\120\SDK\Assemblies\Microsoft.SqlServer.TransactSql.ScriptDom.dll"#>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace=" Microsoft.SqlServer.TransactSql.ScriptDom" #>
<#@ output extension=".cs" #>
using System;
using System.Collections.Generic;
using Microsoft.SqlServer.TransactSql.ScriptDom;
using ScriptDom.SqlDatabase.Test;

namespace ScriptDom.SqlDatabase.Test {
  public partial class DebugVisitor : TSqlConcreteFragmentVisitor {
<#
foreach (var name in typeof(TSqlConcreteFragmentVisitor).GetMethods()
      .Where(m => m.Name == "Visit")
      .Where(m => m.IsVirtual)
      .Where(m => m.IsPublic)
      .Where(m => !m.IsFinal)
      .Select(m => m.GetParameters())
      .Where(ps => ps.Length == 1)
      .Select(ps => ps[0])
      .Select(p => p.ParameterType.Name)) {
#>
    public override void Visit(<#= name #> node) {
      Console.WriteLine("<#= name #>");
      Debug(node);
      base.Visit(node);
    }
<#
}
#>
  }
}

これでこんな感じの cs が吐かれます。

using System;
using System.Collections.Generic;
using Microsoft.SqlServer.TransactSql.ScriptDom;
using ScriptDom.SqlDatabase.Test;

namespace ScriptDom.SqlDatabase.Test {
  public partial class DebugVisitor : TSqlConcreteFragmentVisitor {
    public override void Visit(EventDeclaration node) {
      Console.WriteLine("EventDeclaration");
      Debug(node);
      base.Visit(node);
    }
    ...
  }
}

TSqlConcreteFragmentVisitor クラス (Microsoft.SqlServer.TransactSql.ScriptDom) を継承して、最下層のクラスだけ処理します。
で、partial で必要なとこだけ拡張していきます。

using Microsoft.SqlServer.TransactSql.ScriptDom;
using System;

namespace ScriptDom.SqlDatabase.Test {
  public partial class DebugVisitor {
    public void Debug(TSqlFragment node) { }

    public void Debug(FunctionCall node) {
      Console.WriteLine(node.FunctionName.Value.ToUpper());
    }
  }
}

T4 久しぶりで書き方忘れてる。。