Created
September 8, 2011 00:24
-
-
Save schotime/1202262 to your computer and use it in GitHub Desktop.
Dynamic Sql based on templates
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class SqlBuilder | |
{ | |
Dictionary<string, Clauses> data = new Dictionary<string, Clauses>(); | |
int seq; | |
class Clause | |
{ | |
public string Sql { get; set; } | |
public List<object> Parameters { get; set; } | |
} | |
class Clauses : List<Clause> | |
{ | |
string joiner; | |
string prefix; | |
string postfix; | |
public Clauses(string joiner, string prefix, string postfix) | |
{ | |
this.joiner = joiner; | |
this.prefix = prefix; | |
this.postfix = postfix; | |
} | |
public string ResolveClauses(List<object> finalParams) | |
{ | |
foreach (var item in this) | |
{ | |
item.Sql = Database.ProcessParams(item.Sql, item.Parameters.ToArray(), finalParams); | |
} | |
return prefix + string.Join(joiner, this.Select(c => c.Sql)) + postfix; | |
} | |
} | |
public class Template | |
{ | |
readonly string sql; | |
readonly SqlBuilder builder; | |
private List<object> finalParams = new List<object>(); | |
int dataSeq; | |
public Template(SqlBuilder builder, string sql, params object[] parameters) | |
{ | |
this.sql = Database.ProcessParams(sql, parameters, finalParams); | |
this.builder = builder; | |
} | |
static Regex regex = new Regex(@"\/\*\*.+\*\*\/", RegexOptions.Compiled | RegexOptions.Multiline); | |
void ResolveSql() | |
{ | |
rawSql = sql; | |
if (dataSeq != builder.seq) | |
{ | |
foreach (var pair in builder.data) | |
{ | |
rawSql = rawSql.Replace("/**" + pair.Key + "**/", pair.Value.ResolveClauses(finalParams)); | |
} | |
ReplaceDefaults(); | |
dataSeq = builder.seq; | |
} | |
if (builder.seq == 0) | |
{ | |
ReplaceDefaults(); | |
} | |
} | |
private void ReplaceDefaults() | |
{ | |
foreach (var pair in builder.defaultsIfEmpty) | |
{ | |
rawSql = rawSql.Replace("/**" + pair.Key + "**/", " " + pair.Value + " "); | |
} | |
// replace all that is left with empty | |
rawSql = regex.Replace(rawSql, ""); | |
} | |
string rawSql; | |
public string RawSql { get { ResolveSql(); return rawSql; } } | |
public object Parameters { get { ResolveSql(); return finalParams; } } | |
} | |
public SqlBuilder() | |
{ | |
} | |
public Template AddTemplate(string sql, params object[] parameters) | |
{ | |
return new Template(this, sql, parameters); | |
} | |
void AddClause(string name, string sql, object[] parameters, string joiner, string prefix, string postfix) | |
{ | |
Clauses clauses; | |
if (!data.TryGetValue(name, out clauses)) | |
{ | |
clauses = new Clauses(joiner, prefix, postfix); | |
data[name] = clauses; | |
} | |
clauses.Add(new Clause { Sql = sql, Parameters = new List<object>(parameters) }); | |
seq++; | |
} | |
Dictionary<string, string> defaultsIfEmpty = new Dictionary<string, string> | |
{ | |
{ "where", "1=1" }, | |
}; | |
public SqlBuilder SelectCols(params string[] columns) | |
{ | |
AddClause("selectcols", string.Join(", ", columns), new object[] { }, ", ", ", ", ""); | |
return this; | |
} | |
public SqlBuilder InnerJoin(string sql, params object[] args) | |
{ | |
AddClause("innerjoin", sql, args, "\nINNER JOIN ", "\nINNER JOIN ", "\n"); | |
return this; | |
} | |
public SqlBuilder LeftJoin(string sql, params object[] args) | |
{ | |
AddClause("leftjoin", sql, args, "\nLEFT JOIN ", "\nLEFT JOIN ", "\n"); | |
return this; | |
} | |
public SqlBuilder Where(string sql, params object[] args) | |
{ | |
AddClause("where", sql, args, " AND ", " ( ", " )\n"); | |
return this; | |
} | |
public SqlBuilder OrderBy(string sql, params object[] args) | |
{ | |
AddClause("orderby", sql, args, ", ", "ORDER BY ", "\n"); | |
return this; | |
} | |
public SqlBuilder OrderByCols(params string[] columns) | |
{ | |
AddClause("orderbycols", string.Join(", ", columns), new object[] { }, ", ", ", ", ""); | |
return this; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment