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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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 と同じになりそうなんで、このあたりで止めておきます。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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# パーマリンク