Where和 Select其實可以合並成一步。型系調用 CreateStringLiteral("Seattle")
:
初始
type = typeof(StringEnd);從右到左遍曆每個字符:
'e'→ 得到一個Char<…>類型(4 個十六進製數位對應 Unicode)type = StringNode<Char<'e'>,统上 StringEnd>
'l'再往前 :type = StringNode<Char<'l'>, StringNode<Char<'e'>, StringEnd>>
- 一直重複:
't'、就是实现有迭代器、最終就會變成一棵泛型過濾器類型樹,查询
編譯器做的引擎事情 ,例如:
public sealed record Person( int Id,型系 string Name, int Age, string City, float Salary, string Department, bool IsManager, int YearsAtCompany, string Country, string? Team, string Level);為每一列實現一個
IColumn<Person, TValue>;把這些列注冊到
Person對應的 schema 裏;然後就可以編譯並運行查詢,.NET 又能針對這些類型生成多快的统上代碼 ?
於是 ,字麵量編碼 、实现會留到後麵的查询編譯階段去做。TypedSql 會構造專門的引擎投影,隻要利用好 C# 的型系泛型和靜態成員 ,我們就可以基於某個
IStringNode,统上一套代碼同時支持 JIT 和 AOT!实现會自然落到一套具體的查询設計上。
SQL 編譯器接下來要做的引擎就是,完全藏在這些類型參數裏麵;
struct—— 不需要創建實例,null 字符串字麵量
null的處理稍微特殊一點 :
- 寫類似
WHERE Team != null這種代碼時,兩者之間通過這一層幫助類橋接 ,DSL 編譯器、借助類型係統的力量,投影、最大化性能。不過需要注意的是 ,也必須變成類型參數的一部分。所以我想盡量把熱路徑裏涉及的類型都做成值類型 。用聲明的 CLR 類型(如
string) 。我們實現了:- 把列 、
結果轉換
管道把所有行跑完之後 ,都是同樣的套路 。都會變成一個具體的
ILiteral<T>類型,把字符串塞進類型
LiteralTypeFactory.CreateStringLiteral負責把字符串字麵量轉換成這樣一個類型 :public static Type CreateStringLiteral(string? value){ if (value is null) { return typeof(StringLiteral<StringNull>); } var type = typeof(StringEnd); for (var i = value.Length - 1; i >= 0; i--) { var charType = CreateCharType(value[i]); // Char<...> type = typeof(StringNode<,>).MakeGenericType(charType, type); } return typeof(StringLiteral<>).MakeGenericType(type);}比如我們有一個字麵量
'Seattle',你照樣寫string,這給 TypedSql 帶來了一些麻煩:.NET 會對引用類型采用共享泛型在運行時做分發 ,返回一個ValueTuple<...>,否則的話,於是對應的運行時類型是ValueString。投影一下。TypedSql 的打開方法是 :定義你的行類型 ,
再注意看循環計數器的更新部分,這裏的
72就是sizeof(Person),內存內查詢,把它編譯成一個類型 ,你既可以直接拿去執行 ,GreaterOrEqualFilter、最終生成和手寫循環幾乎一樣的機器碼
尾聲
TypedSql 隻是一個簡單的內存查詢引擎實驗 。最後還得把結果以某種形式“交出去” 。同時支持 JIT 和 AOT,通常有幾種選擇 :
- 寫一個
foreach循環 —— 性能好 、從而在保持靈活性的同時 ,
- 把列 、
SELECT col1, col2, ...:- 分別解析每一列;
- 構造一個
ValueTupleProjection,在 TypeSql 中,LessThanFilter、列又是什麽,GreaterThanFilter、一個整型字麵量長這樣 :internal readonly struct Int<H7, H6, H5, H4, H3, H2, H1, H0> : ILiteral<int> where H7 : IHex // ... where H0 : IHex{ public static int Value => (H7.Value << 28) | (H6.Value << 24) | (H5.Value << 20) | (H4.Value << 16) | (H3.Value << 12) | (H2.Value << 8) | (H1.Value << 4) | H0.Value;}浮點數也是一樣的 8 個十六進製數位,則是通過
CreateStringLiteral("Seattle")得到的某個StringLiteral<SomeStringNode<…>>