[C#] パイプで繋げて、データベースを検索

ふと、|演算子(パイプ演算子)を使って、データベースのストリームを検索できたら、何かできるのではなかろうか…と骨休めがてらちょっと。

public class Test
{
	public void test001()
	{
		var db = new DB{ ConnectionString=""};
		RESULT items = db | "person" |
			"familyname".EQ("masuda") |
			"age".GE(20) |
			"*";
		RESULT items2 = db | "person" |
			"familyname".EQ("masuda") |
			"age".GE(20) |
			"id" | "familyname" | "lastname";
	}
	public void test002()
	{
		var db = new DB { ConnectionString = "" };
		RESULT items = 
			db | "person" |
			(EQ)"familyname" % "masuda" |	// familyname == "masuda" と同じ
			(UP)"age" % 20 |				// age >= 20 と同じ
			"*";
	}
	public void test003()
	{
		// これが直感的で良い
		var db = new DB { ConnectionString = "" };
		RESULT items =
			db | "person" |					// テーブルを指定
			(OP)"familyname" == "masuda" |	// 検索条件
			(OP)"age" >= 20 |				
			"*";							// 出力
	}
}

データストリームというよりも、擬似LINQ構文になっちゃった感じで、あまり意味がありませんが。|演算子のオーバーライドと、暗黙の型変換(implicit)を駆使すると、こんな風に書けますという例です。
データの比較を行うときに、”カラム名”.EQ(値) のように、最初はメソッド名を考えてみたのですが、あまり可読性がよくないので、「==演算子」等もオーバーライドすることにしました。

OP クラスのところが肝で、テーブルのカラム名(文字列)を一度 OP クラスにキャストしてから使うという妙な技をつかっています。このあたりは、もう少ししっかりと作れば、LINQ と同じになるんでしょうが、しっかり作ってしまうと LINQ と同じになりそうなんで、このあたりで止めておきます。

上記のコードをコンパイルするためのクラス群は以下になります。コンパイルするためだけなので、中身は作っていませんが、まあ、構造が分かるかと。本来はパイプで使うわけだから、グラフィック系のフィルターのようにしたいですよね。ちょっとそのあたりの例は思案中ということで。

public class DB
{
	private SqlConnection _cn;
	public string ConnectionString { get; set; }
	public static DB operator |(DB db, string name)
	{
		return db;
	}
	public static DB operator |(DB db, OP op)
	{
		return db;
	}
	public static implicit operator RESULT(DB db)
	{
		return new RESULT();
	}
}

public static class DPipeExtentions
{
	public static OP EQ( this string cname, object val )
	{
		return new OP { ColumnName = cname, Value= val, OpCode = OP.OPRATOR.EQ };
	}
	public static OP NE( this string cname, object val )
	{
		return new OP { ColumnName = cname, Value= val, OpCode = OP.OPRATOR.NE };
	}
	public static OP LE(this string cname, object val)
	{
		return new OP { ColumnName = cname, Value = val, OpCode = OP.OPRATOR.LE };
	}
	public static OP LT(this string cname, object val)
	{
		return new OP { ColumnName = cname, Value = val, OpCode = OP.OPRATOR.LT };
	}
	public static OP GE(this string cname, object val)
	{
		return new OP { ColumnName = cname, Value = val, OpCode = OP.OPRATOR.GE };
	}
	public static OP GT(this string cname, object val)
	{
		return new OP { ColumnName = cname, Value = val, OpCode = OP.OPRATOR.GT };
	}
}
public class OP
{
	public enum OPRATOR {
		EQ, NE, LT, LE, GT,GE,
	}
	public OPRATOR OpCode { get; set; }
	public string ColumnName { get; set; }
	public object Value { get; set; }
	public static OP operator %(OP op, object val)
	{
		op.Value = val;
		return op;
	}
	public static implicit operator OP(string name ) {
		return new OP{ ColumnName = name };
	}
	public static OP operator ==(OP op, object val) { 
		return new OP { ColumnName = op.ColumnName, Value = val, OpCode = OPRATOR.EQ };
	}
	public static OP operator !=(OP op, object val)
	{
		return new OP { ColumnName = op.ColumnName, Value = val, OpCode = OPRATOR.NE };
	}
	public static OP operator <(OP op, object val)
	{
		return new OP { ColumnName = op.ColumnName, Value = val, OpCode = OPRATOR.LT };
	}
	public static OP operator <=(OP op, object val)
	{
		return new OP { ColumnName = op.ColumnName, Value = val, OpCode = OPRATOR.LE };
	}
	public static OP operator >(OP op, object val)
	{
		return new OP { ColumnName = op.ColumnName, Value = val, OpCode = OPRATOR.GT };
	}
	public static OP operator >=(OP op, object val)
	{
		return new OP { ColumnName = op.ColumnName, Value = val, OpCode = OPRATOR.GE };
	}
	public override bool Equals(object obj)
	{
		return base.Equals(obj);
	}
	public override int GetHashCode()
	{
		return base.GetHashCode();
	}
}
public class RESULT : List<object>
{
}
public class EQ : OP
{
	public static implicit operator EQ(string name)
	{
		return (EQ)new OP { ColumnName = name, OpCode = OPRATOR.EQ };
	}
}
public class UP : OP
{
	public static implicit operator UP(string name)
	{
		return (UP)new OP { ColumnName = name, OpCode = OPRATOR.GE };
	}
}
カテゴリー: C# パーマリンク