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