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