mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-08-02 09:55:57 +08:00
initial commit
This commit is contained in:
217
Providers/FreeSql.Provider.QuestDb/Curd/OnConflictDoUpdate.cs
Normal file
217
Providers/FreeSql.Provider.QuestDb/Curd/OnConflictDoUpdate.cs
Normal file
@ -0,0 +1,217 @@
|
||||
using FreeSql.Aop;
|
||||
using FreeSql.Internal.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FreeSql.QuestDb.Curd
|
||||
{
|
||||
public class OnConflictDoUpdate<T1> where T1 : class
|
||||
{
|
||||
internal QuestDbInsert<T1> _pgsqlInsert;
|
||||
internal QuestDbUpdate<T1> _pgsqlUpdatePriv;
|
||||
internal QuestDbUpdate<T1> _pgsqlUpdate => _pgsqlUpdatePriv ??
|
||||
(_pgsqlUpdatePriv = new QuestDbUpdate<T1>(_pgsqlInsert.InternalOrm, _pgsqlInsert.InternalCommonUtils, _pgsqlInsert.InternalCommonExpression, null) { InternalTableAlias = "EXCLUDED" }
|
||||
.NoneParameter().SetSource(_pgsqlInsert.InternalSource) as QuestDbUpdate<T1>);
|
||||
internal ColumnInfo[] _tempPrimarys;
|
||||
bool _doNothing;
|
||||
|
||||
public OnConflictDoUpdate(IInsert<T1> insert, Expression<Func<T1, object>> columns = null)
|
||||
{
|
||||
_pgsqlInsert = insert as QuestDbInsert<T1>;
|
||||
if (_pgsqlInsert == null) throw new Exception(CoreStrings.S_Features_Unique("OnConflictDoUpdate", "QuestDb"));
|
||||
if (_pgsqlInsert._noneParameterFlag == "c") _pgsqlInsert._noneParameterFlag = "cu";
|
||||
|
||||
if (columns != null)
|
||||
{
|
||||
var colsList = new List<ColumnInfo>();
|
||||
var cols = _pgsqlInsert.InternalCommonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, null, columns?.Body, false, null).ToDictionary(a => a, a => true);
|
||||
foreach (var col in _pgsqlInsert.InternalTable.Columns.Values)
|
||||
if (cols.ContainsKey(col.Attribute.Name))
|
||||
colsList.Add(col);
|
||||
_tempPrimarys = colsList.ToArray();
|
||||
}
|
||||
if (_tempPrimarys == null || _tempPrimarys.Any() == false)
|
||||
_tempPrimarys = _pgsqlInsert.InternalTable.Primarys;
|
||||
if (_tempPrimarys.Any() == false) throw new Exception(CoreStrings.S_OnConflictDoUpdate_MustIsPrimary);
|
||||
}
|
||||
|
||||
protected void ClearData()
|
||||
{
|
||||
_pgsqlInsert.InternalClearData();
|
||||
_pgsqlUpdatePriv = null;
|
||||
}
|
||||
|
||||
public OnConflictDoUpdate<T1> IgnoreColumns(Expression<Func<T1, object>> columns)
|
||||
{
|
||||
_pgsqlUpdate.IgnoreColumns(columns);
|
||||
return this;
|
||||
}
|
||||
public OnConflictDoUpdate<T1> UpdateColumns(Expression<Func<T1, object>> columns)
|
||||
{
|
||||
_pgsqlUpdate.UpdateColumns(columns);
|
||||
return this;
|
||||
}
|
||||
public OnConflictDoUpdate<T1> IgnoreColumns(string[] columns)
|
||||
{
|
||||
_pgsqlUpdate.IgnoreColumns(columns);
|
||||
return this;
|
||||
}
|
||||
public OnConflictDoUpdate<T1> UpdateColumns(string[] columns)
|
||||
{
|
||||
_pgsqlUpdate.UpdateColumns(columns);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OnConflictDoUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> column, TMember value)
|
||||
{
|
||||
_pgsqlUpdate.Set(column, value);
|
||||
return this;
|
||||
}
|
||||
//由于表达式解析问题,ON CONFLICT("id") DO UPDATE SET 需要指定表别名,如 Set(a => a.Clicks + 1) 解析会失败
|
||||
//暂时不开放这个功能,如有需要使用 SetRaw("click = t.click + 1") 替代该操作
|
||||
//public OnConflictDoUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> exp)
|
||||
//{
|
||||
// _pgsqlUpdate.Set(exp);
|
||||
// return this;
|
||||
//}
|
||||
public OnConflictDoUpdate<T1> SetRaw(string sql)
|
||||
{
|
||||
_pgsqlUpdate.SetRaw(sql);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OnConflictDoUpdate<T1> DoNothing()
|
||||
{
|
||||
_doNothing = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public string ToSql()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(_pgsqlInsert.ToSql()).Append("\r\nON CONFLICT(");
|
||||
for (var a = 0; a < _tempPrimarys.Length; a++)
|
||||
{
|
||||
if (a > 0) sb.Append(", ");
|
||||
sb.Append(_pgsqlInsert.InternalCommonUtils.QuoteSqlName(_tempPrimarys[a].Attribute.Name));
|
||||
}
|
||||
if (_doNothing)
|
||||
{
|
||||
sb.Append(") DO NOTHING");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(") DO UPDATE SET\r\n");
|
||||
|
||||
if (_pgsqlUpdate._tempPrimarys.Any() == false) _pgsqlUpdate._tempPrimarys = _tempPrimarys;
|
||||
var sbSetEmpty = _pgsqlUpdate.InternalSbSet.Length == 0;
|
||||
var sbSetIncrEmpty = _pgsqlUpdate.InternalSbSetIncr.Length == 0;
|
||||
if (sbSetEmpty == false || sbSetIncrEmpty == false)
|
||||
{
|
||||
if (sbSetEmpty == false) sb.Append(_pgsqlUpdate.InternalSbSet.ToString().Substring(2));
|
||||
if (sbSetIncrEmpty == false) sb.Append(sbSetEmpty ? _pgsqlUpdate.InternalSbSetIncr.ToString().Substring(2) : _pgsqlUpdate.InternalSbSetIncr.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
var colidx = 0;
|
||||
foreach (var col in _pgsqlInsert.InternalTable.Columns.Values)
|
||||
{
|
||||
if (col.Attribute.IsPrimary || _pgsqlUpdate.InternalIgnore.ContainsKey(col.Attribute.Name)) continue;
|
||||
|
||||
if (colidx > 0) sb.Append(", \r\n");
|
||||
|
||||
if (col.Attribute.IsVersion == true && col.Attribute.MapType != typeof(byte[]))
|
||||
{
|
||||
var field = _pgsqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
|
||||
sb.Append(field).Append(" = ").Append(_pgsqlInsert.InternalCommonUtils.QuoteSqlName(_pgsqlInsert.InternalTable.DbName)).Append(".").Append(field).Append(" + 1");
|
||||
}
|
||||
else if (_pgsqlInsert.InternalIgnore.ContainsKey(col.Attribute.Name))
|
||||
{
|
||||
if (string.IsNullOrEmpty(col.DbUpdateValue) == false)
|
||||
{
|
||||
sb.Append(_pgsqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name)).Append(" = ").Append(col.DbUpdateValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
var caseWhen = _pgsqlUpdate.InternalWhereCaseSource(col.CsName, sqlval => sqlval).Trim();
|
||||
sb.Append(caseWhen);
|
||||
if (caseWhen.EndsWith(" END")) _pgsqlUpdate.InternalToSqlCaseWhenEnd(sb, col);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var field = _pgsqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
|
||||
sb.Append(field).Append(" = EXCLUDED.").Append(field);
|
||||
}
|
||||
++colidx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public long ExecuteAffrows()
|
||||
{
|
||||
var sql = this.ToSql();
|
||||
if (string.IsNullOrEmpty(sql)) return 0;
|
||||
|
||||
var before = new CurdBeforeEventArgs(_pgsqlInsert.InternalTable.Type, _pgsqlInsert.InternalTable, CurdType.Insert, sql, _pgsqlInsert.InternalParams);
|
||||
_pgsqlInsert.InternalOrm.Aop.CurdBeforeHandler?.Invoke(_pgsqlInsert, before);
|
||||
long ret = 0;
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
ret = _pgsqlInsert.InternalOrm.Ado.ExecuteNonQuery(_pgsqlInsert.InternalConnection, _pgsqlInsert.InternalTransaction, CommandType.Text, sql, _pgsqlInsert._commandTimeout, _pgsqlInsert.InternalParams);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new CurdAfterEventArgs(before, exception, ret);
|
||||
_pgsqlInsert.InternalOrm.Aop.CurdAfterHandler?.Invoke(_pgsqlInsert, after);
|
||||
ClearData();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if net40
|
||||
#else
|
||||
async public Task<long> ExecuteAffrowsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var sql = this.ToSql();
|
||||
if (string.IsNullOrEmpty(sql)) return 0;
|
||||
|
||||
var before = new CurdBeforeEventArgs(_pgsqlInsert.InternalTable.Type, _pgsqlInsert.InternalTable, CurdType.Insert, sql, _pgsqlInsert.InternalParams);
|
||||
_pgsqlInsert.InternalOrm.Aop.CurdBeforeHandler?.Invoke(_pgsqlInsert, before);
|
||||
long ret = 0;
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
ret = await _pgsqlInsert.InternalOrm.Ado.ExecuteNonQueryAsync(_pgsqlInsert.InternalConnection, _pgsqlInsert.InternalTransaction, CommandType.Text, sql, _pgsqlInsert._commandTimeout, _pgsqlInsert.InternalParams, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new CurdAfterEventArgs(before, exception, ret);
|
||||
_pgsqlInsert.InternalOrm.Aop.CurdAfterHandler?.Invoke(_pgsqlInsert, after);
|
||||
ClearData();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
32
Providers/FreeSql.Provider.QuestDb/Curd/QuestDbDelete.cs
Normal file
32
Providers/FreeSql.Provider.QuestDb/Curd/QuestDbDelete.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using FreeSql.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FreeSql.QuestDb.Curd
|
||||
{
|
||||
|
||||
class QuestDbDelete<T1> : Internal.CommonProvider.DeleteProvider<T1>
|
||||
{
|
||||
public QuestDbDelete(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
|
||||
: base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override List<T1> ExecuteDeleted() => throw new NotImplementedException("QuestDb 不支持删除数据.");
|
||||
|
||||
public override int ExecuteAffrows() => throw new NotImplementedException("QuestDb 不支持删除数据.");
|
||||
|
||||
#if net40
|
||||
#else
|
||||
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException("QuestDb 不支持删除数据.");
|
||||
|
||||
public override Task<List<T1>> ExecuteDeletedAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException("QuestDb 不支持删除数据.");
|
||||
#endif
|
||||
}
|
||||
}
|
288
Providers/FreeSql.Provider.QuestDb/Curd/QuestDbInsert.cs
Normal file
288
Providers/FreeSql.Provider.QuestDb/Curd/QuestDbInsert.cs
Normal file
@ -0,0 +1,288 @@
|
||||
using FreeSql.Internal;
|
||||
using FreeSql.Internal.Model;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FreeSql.QuestDb.Curd
|
||||
{
|
||||
class QuestDbInsert<T1> : Internal.CommonProvider.InsertProvider<T1> where T1 : class
|
||||
{
|
||||
public QuestDbInsert(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
|
||||
: base(orm, commonUtils, commonExpression)
|
||||
{
|
||||
}
|
||||
|
||||
internal IFreeSql InternalOrm => _orm;
|
||||
internal TableInfo InternalTable => _table;
|
||||
internal DbParameter[] InternalParams => _params;
|
||||
internal DbConnection InternalConnection => _connection;
|
||||
internal DbTransaction InternalTransaction => _transaction;
|
||||
internal CommonUtils InternalCommonUtils => _commonUtils;
|
||||
internal CommonExpression InternalCommonExpression => _commonExpression;
|
||||
internal List<T1> InternalSource => _source;
|
||||
internal Dictionary<string, bool> InternalIgnore => _ignore;
|
||||
internal void InternalClearData() => ClearData();
|
||||
internal string InternalTableRuleInvoke() => TableRuleInvoke();
|
||||
|
||||
private int InternelExecuteAffrows()
|
||||
{
|
||||
//如果设置了RestAPI的Url则走HTTP
|
||||
var sql = ToSql();
|
||||
var execAsync = RestAPIExtension.ExecAsync(sql).GetAwaiter().GetResult();
|
||||
var resultHash = new Hashtable();
|
||||
try
|
||||
{
|
||||
resultHash = JsonConvert.DeserializeObject<Hashtable>(execAsync);
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (execAsync.Contains("401"))
|
||||
{
|
||||
throw new Exception("请确认new FreeSqlBuilder().UseQuestDbRestAPI()中设置的用户名密码是否正确.");
|
||||
}
|
||||
}
|
||||
var ddl = resultHash["ddl"]?.ToString();
|
||||
return ddl?.ToLower() == "ok" ? 1 : 0;
|
||||
}
|
||||
|
||||
public override int ExecuteAffrows()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(RestAPIExtension.BaseUrl))
|
||||
{
|
||||
return base.SplitExecuteAffrows(_batchValuesLimit > 0 ? _batchValuesLimit : 5000,
|
||||
_batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||
}
|
||||
return InternelExecuteAffrows();
|
||||
}
|
||||
|
||||
public override long ExecuteIdentity() => base.SplitExecuteIdentity(
|
||||
_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||
|
||||
public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(
|
||||
_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||
|
||||
protected override long RawExecuteIdentity()
|
||||
{
|
||||
var sql = this.ToSql();
|
||||
if (string.IsNullOrEmpty(sql)) return 0;
|
||||
|
||||
long ret = 0;
|
||||
Exception exception = null;
|
||||
Aop.CurdBeforeEventArgs before = null;
|
||||
|
||||
var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity == true);
|
||||
if (identCols.Any() == false)
|
||||
{
|
||||
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
|
||||
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||
try
|
||||
{
|
||||
ret = _orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _commandTimeout,
|
||||
_params);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
|
||||
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sql = string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name));
|
||||
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
|
||||
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||
try
|
||||
{
|
||||
long.TryParse(
|
||||
string.Concat(_orm.Ado.ExecuteScalar(_connection, _transaction, CommandType.Text, sql,
|
||||
_commandTimeout, _params)), out ret);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
|
||||
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected override List<T1> RawExecuteInserted()
|
||||
{
|
||||
var sql = this.ToSql();
|
||||
if (string.IsNullOrEmpty(sql)) return new List<T1>();
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(sql).Append(" RETURNING ");
|
||||
|
||||
var colidx = 0;
|
||||
foreach (var col in _table.Columns.Values)
|
||||
{
|
||||
if (colidx > 0) sb.Append(", ");
|
||||
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ")
|
||||
.Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||
++colidx;
|
||||
}
|
||||
|
||||
sql = sb.ToString();
|
||||
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
|
||||
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||
var ret = new List<T1>();
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
ret = _orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text,
|
||||
sql, _commandTimeout, _params);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
|
||||
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if net40
|
||||
#else
|
||||
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(RestAPIExtension.BaseUrl))
|
||||
{
|
||||
return base.SplitExecuteAffrowsAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000,
|
||||
_batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
|
||||
}
|
||||
return Task.FromResult(InternelExecuteAffrows());
|
||||
}
|
||||
|
||||
|
||||
public override Task<long> ExecuteIdentityAsync(CancellationToken cancellationToken = default) =>
|
||||
base.SplitExecuteIdentityAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000,
|
||||
_batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
|
||||
|
||||
public override Task<List<T1>> ExecuteInsertedAsync(CancellationToken cancellationToken = default) =>
|
||||
base.SplitExecuteInsertedAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000,
|
||||
_batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
|
||||
|
||||
async protected override Task<long> RawExecuteIdentityAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var sql = this.ToSql();
|
||||
if (string.IsNullOrEmpty(sql)) return 0;
|
||||
|
||||
long ret = 0;
|
||||
Exception exception = null;
|
||||
Aop.CurdBeforeEventArgs before = null;
|
||||
|
||||
var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity == true);
|
||||
if (identCols.Any() == false)
|
||||
{
|
||||
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
|
||||
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||
try
|
||||
{
|
||||
ret = await _orm.Ado.ExecuteNonQueryAsync(_connection, _transaction, CommandType.Text, sql,
|
||||
_commandTimeout, _params, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
|
||||
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sql = string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name));
|
||||
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
|
||||
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||
try
|
||||
{
|
||||
long.TryParse(
|
||||
string.Concat(await _orm.Ado.ExecuteScalarAsync(_connection, _transaction, CommandType.Text, sql,
|
||||
_commandTimeout, _params, cancellationToken)), out ret);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
|
||||
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
async protected override Task<List<T1>> RawExecuteInsertedAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var sql = this.ToSql();
|
||||
if (string.IsNullOrEmpty(sql)) return new List<T1>();
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(sql).Append(" RETURNING ");
|
||||
|
||||
var colidx = 0;
|
||||
foreach (var col in _table.Columns.Values)
|
||||
{
|
||||
if (colidx > 0) sb.Append(", ");
|
||||
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ")
|
||||
.Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||
++colidx;
|
||||
}
|
||||
|
||||
sql = sb.ToString();
|
||||
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
|
||||
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||
var ret = new List<T1>();
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
ret = await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction,
|
||||
CommandType.Text, sql, _commandTimeout, _params, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
|
||||
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
using FreeSql.Internal;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace FreeSql.QuestDb.Curd
|
||||
{
|
||||
|
||||
class QuestDbInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
|
||||
{
|
||||
public QuestDbInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
|
||||
: base(orm, commonUtils, commonExpression)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql()
|
||||
{
|
||||
var dbParams = new List<DbParameter>();
|
||||
if (_sourceSql != null)
|
||||
{
|
||||
var data = new List<T1>();
|
||||
data.Add((T1)_table.Type.CreateInstanceGetDefaultValue());
|
||||
var sql = getInsertSql(data, false, false);
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(sql.Substring(0, sql.IndexOf(") VALUES")));
|
||||
sb.Append(") \r\n");
|
||||
WriteSourceSelectUnionAll(null, sb, null);
|
||||
sb.Append(sql.Substring(sql.IndexOf("\r\nON CONFLICT(") + 2));
|
||||
return sb.ToString();
|
||||
}
|
||||
if (_source?.Any() != true) return null;
|
||||
|
||||
var sqls = new string[2];
|
||||
var ds = SplitSourceByIdentityValueIsNull(_source);
|
||||
if (ds.Item1.Any()) sqls[0] = string.Join("\r\n\r\n;\r\n\r\n", ds.Item1.Select(a => getInsertSql(a, false, true)));
|
||||
if (ds.Item2.Any()) sqls[1] = string.Join("\r\n\r\n;\r\n\r\n", ds.Item2.Select(a => getInsertSql(a, true, true)));
|
||||
_params = dbParams.ToArray();
|
||||
if (ds.Item2.Any() == false) return sqls[0];
|
||||
if (ds.Item1.Any() == false) return sqls[1];
|
||||
return string.Join("\r\n\r\n;\r\n\r\n", sqls);
|
||||
|
||||
string getInsertSql(List<T1> data, bool flagInsert, bool noneParameter)
|
||||
{
|
||||
var insert = _orm.Insert<T1>()
|
||||
.AsTable(_tableRule).AsType(_table.Type)
|
||||
.WithConnection(_connection)
|
||||
.WithTransaction(_transaction)
|
||||
.NoneParameter(noneParameter) as Internal.CommonProvider.InsertProvider<T1>;
|
||||
insert._source = data;
|
||||
insert._table = _table;
|
||||
insert._noneParameterFlag = flagInsert ? "cuc" : "cu";
|
||||
|
||||
string sql = "";
|
||||
if (IdentityColumn != null && flagInsert) sql = insert.ToSql();
|
||||
else
|
||||
{
|
||||
var ocdu = new OnConflictDoUpdate<T1>(insert.InsertIdentity());
|
||||
ocdu._tempPrimarys = _tempPrimarys;
|
||||
var cols = _table.Columns.Values.Where(a => _updateSetDict.ContainsKey(a.Attribute.Name) ||
|
||||
_tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
|
||||
ocdu.UpdateColumns(cols.Select(a => a.Attribute.Name).ToArray());
|
||||
if (_doNothing == true || cols.Any() == false)
|
||||
ocdu.DoNothing();
|
||||
sql = ocdu.ToSql();
|
||||
|
||||
if (_updateSetDict.Any())
|
||||
{
|
||||
var findregex = new Regex("(t1|t2)." + _commonUtils.QuoteSqlName("test").Replace("test", "(\\w+)"));
|
||||
var tableName = _commonUtils.QuoteSqlName(TableRuleInvoke());
|
||||
foreach (var usd in _updateSetDict)
|
||||
{
|
||||
var field = _commonUtils.QuoteSqlName(usd.Key);
|
||||
var findsql = $"{field} = EXCLUDED.{field}";
|
||||
var usdval = findregex.Replace(usd.Value, m =>
|
||||
{
|
||||
if (m.Groups[1].Value == "t1") return $"{tableName}.{_commonUtils.QuoteSqlName(m.Groups[2].Value)}";
|
||||
return $"EXCLUDED.{_commonUtils.QuoteSqlName(m.Groups[2].Value)}";
|
||||
});
|
||||
sql = sql.Replace(findsql, $"{field} = {usdval}");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(sql)) return null;
|
||||
if (insert._params?.Any() == true) dbParams.AddRange(insert._params);
|
||||
return sql;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
644
Providers/FreeSql.Provider.QuestDb/Curd/QuestDbSelect.cs
Normal file
644
Providers/FreeSql.Provider.QuestDb/Curd/QuestDbSelect.cs
Normal file
@ -0,0 +1,644 @@
|
||||
using FreeSql.Internal;
|
||||
using FreeSql.Internal.Model;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace FreeSql.QuestDb.Curd
|
||||
{
|
||||
class QuestDbSelect<T1> : FreeSql.Internal.CommonProvider.Select1Provider<T1>
|
||||
{
|
||||
internal static string ToSqlStatic(CommonUtils _commonUtils, CommonExpression _commonExpression, string _select,
|
||||
bool _distinct, string field, StringBuilder _join, StringBuilder _where, string _groupby, string _having,
|
||||
string _orderby, int _skip, int _limit, List<SelectTableInfo> _tables,
|
||||
List<Dictionary<Type, string>> tbUnions, Func<Type, string, string> _aliasRule, string _tosqlAppendContent,
|
||||
List<GlobalFilter.Item> _whereGlobalFilter, IFreeSql _orm)
|
||||
{
|
||||
if (_orm.CodeFirst.IsAutoSyncStructure)
|
||||
_orm.CodeFirst.SyncStructure(_tables.Select(a => a.Table.Type).ToArray());
|
||||
|
||||
if (_whereGlobalFilter.Any())
|
||||
foreach (var tb in _tables.Where(a => a.Type != SelectTableInfoType.Parent))
|
||||
{
|
||||
tb.Cascade = _commonExpression.GetWhereCascadeSql(tb, _whereGlobalFilter.Where(a => a.Before == false), true);
|
||||
tb.CascadeBefore = _commonExpression.GetWhereCascadeSql(tb, _whereGlobalFilter.Where(a => a.Before == true), true);
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
var tbUnionsGt0 = tbUnions.Count > 1;
|
||||
for (var tbUnionsIdx = 0; tbUnionsIdx < tbUnions.Count; tbUnionsIdx++)
|
||||
{
|
||||
if (tbUnionsIdx > 0) sb.Append("\r\n \r\nUNION ALL\r\n \r\n");
|
||||
if (tbUnionsGt0) sb.Append(_select).Append(" * from (");
|
||||
var tbUnion = tbUnions[tbUnionsIdx];
|
||||
|
||||
var sbnav = new StringBuilder();
|
||||
sb.Append(_select);
|
||||
if (_distinct) sb.Append("DISTINCT ");
|
||||
sb.Append(field).Append(" \r\nFROM ");
|
||||
var tbsjoin = _tables.Where(a => a.Type != SelectTableInfoType.From).ToArray();
|
||||
var tbsfrom = _tables.Where(a => a.Type == SelectTableInfoType.From).ToArray();
|
||||
for (var a = 0; a < tbsfrom.Length; a++)
|
||||
{
|
||||
sb.Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[a].Table.Type])).Append(" ")
|
||||
.Append(_aliasRule?.Invoke(tbsfrom[a].Table.Type, tbsfrom[a].Alias) ?? tbsfrom[a].Alias);
|
||||
if (tbsjoin.Length > 0)
|
||||
{
|
||||
//如果存在 join 查询,则处理 from t1, t2 改为 from t1 inner join t2 on 1 = 1
|
||||
for (var b = 1; b < tbsfrom.Length; b++)
|
||||
{
|
||||
sb.Append(" \r\nLEFT JOIN ")
|
||||
.Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[b].Table.Type])).Append(" ")
|
||||
.Append(_aliasRule?.Invoke(tbsfrom[b].Table.Type, tbsfrom[b].Alias) ??
|
||||
tbsfrom[b].Alias);
|
||||
|
||||
if (string.IsNullOrEmpty(tbsfrom[b].NavigateCondition) &&
|
||||
string.IsNullOrEmpty(tbsfrom[b].On) &&
|
||||
string.IsNullOrEmpty(tbsfrom[b].Cascade) &&
|
||||
string.IsNullOrEmpty(tbsfrom[b].CascadeBefore)) sb.Append(" ON 1 = 1");
|
||||
else sb.Append(" ON ").Append(string.Join(" AND ", new[]
|
||||
{
|
||||
tbsfrom[b].CascadeBefore,
|
||||
tbsfrom[b].NavigateCondition ?? tbsfrom[b].On,
|
||||
tbsfrom[b].Cascade
|
||||
}.Where(sql => string.IsNullOrEmpty(sql) == false)));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].CascadeBefore)) sbnav.Append(" AND ").Append(tbsfrom[a].CascadeBefore);
|
||||
if (!string.IsNullOrEmpty(tbsfrom[a].NavigateCondition)) sbnav.Append(" AND (").Append(tbsfrom[a].NavigateCondition).Append(")");
|
||||
if (!string.IsNullOrEmpty(tbsfrom[a].On)) sbnav.Append(" AND (").Append(tbsfrom[a].On).Append(")");
|
||||
if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].Cascade)) sbnav.Append(" AND ").Append(tbsfrom[a].Cascade);
|
||||
}
|
||||
|
||||
if (a < tbsfrom.Length - 1) sb.Append(", ");
|
||||
}
|
||||
|
||||
foreach (var tb in tbsjoin)
|
||||
{
|
||||
switch (tb.Type)
|
||||
{
|
||||
case SelectTableInfoType.Parent:
|
||||
case SelectTableInfoType.RawJoin:
|
||||
continue;
|
||||
case SelectTableInfoType.LeftJoin:
|
||||
sb.Append(" \r\nLEFT JOIN ");
|
||||
break;
|
||||
case SelectTableInfoType.InnerJoin:
|
||||
sb.Append(" \r\nINNER JOIN ");
|
||||
break;
|
||||
case SelectTableInfoType.RightJoin:
|
||||
sb.Append(" \r\nRIGHT JOIN ");
|
||||
break;
|
||||
}
|
||||
sb.Append(_commonUtils.QuoteSqlName(tbUnion[tb.Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tb.Table.Type, tb.Alias) ?? tb.Alias)
|
||||
.Append(" ON ").Append(string.Join(" AND ", new[]
|
||||
{
|
||||
tb.CascadeBefore,
|
||||
tb.On ?? tb.NavigateCondition,
|
||||
tb.Cascade
|
||||
}.Where(sql => string.IsNullOrEmpty(sql) == false)));
|
||||
if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition))sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
|
||||
}
|
||||
|
||||
if (_join.Length > 0) sb.Append(_join);
|
||||
|
||||
if (!string.IsNullOrEmpty(_tables[0].CascadeBefore)) sbnav.Append(" AND ").Append(_tables[0].CascadeBefore);
|
||||
sbnav.Append(_where);
|
||||
if (!string.IsNullOrEmpty(_tables[0].Cascade)) sbnav.Append(" AND ").Append(_tables[0].Cascade);
|
||||
|
||||
if (sbnav.Length > 0)
|
||||
{
|
||||
sb.Append(" \r\nWHERE ").Append(sbnav.Remove(0, 5));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(_groupby) == false)
|
||||
{
|
||||
//sb.Append(_groupby);
|
||||
if (string.IsNullOrEmpty(_having) == false)
|
||||
{
|
||||
var message = @"提示:由于QuedtDb语法不支持Having,请使用以下语法代替:
|
||||
fsql.Select<Model>()
|
||||
//.GroupBy(a => a.Id)
|
||||
//.Having(a => a.Count() > 1)
|
||||
.WithTempQuery(a => new
|
||||
{
|
||||
a.Id,
|
||||
count1 = SqlExt.Count(a.Id).ToValue()
|
||||
})
|
||||
.Where(a => a.count1 > 1)
|
||||
.ToList();";
|
||||
throw new NotImplementedException(message);
|
||||
}
|
||||
}
|
||||
|
||||
sb.Append(_orderby);
|
||||
|
||||
//SamoleBy扩展
|
||||
if (SampleByExtension.IsExistence.Value)
|
||||
{
|
||||
sb.Append(SampleByExtension.SamoleByString.Value);
|
||||
SampleByExtension.Initialize();
|
||||
}
|
||||
|
||||
//LatestOn扩展
|
||||
if (LatestOnExtension.IsExistence.Value)
|
||||
{
|
||||
sb.Append(LatestOnExtension.LatestOnString.Value);
|
||||
LatestOnExtension.Initialize();
|
||||
}
|
||||
|
||||
if (_limit > 0)
|
||||
sb.Append(" \r\nlimit ").Append(_skip == 0 ? _limit : _skip);
|
||||
if (_skip > 0)
|
||||
//sb.Append(" \r\noffset ").Append(_skip);
|
||||
sb.Append(",").Append(_skip + _limit);
|
||||
|
||||
sbnav.Clear();
|
||||
if (tbUnionsGt0) sb.Append(") ftb");
|
||||
}
|
||||
|
||||
return sb.Append(_tosqlAppendContent).ToString();
|
||||
}
|
||||
|
||||
public QuestDbSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) :
|
||||
base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public override ISelect<T1, T2> From<T2>(
|
||||
Expression<Func<ISelectFromExpression<T1>, T2, ISelectFromExpression<T1>>> exp)
|
||||
{
|
||||
this.InternalFrom(exp);
|
||||
var ret = new QuestDbSelect<T1, T2>(_orm, _commonUtils, _commonExpression, null);
|
||||
QuestDbSelect<T1>.CopyData(this, ret, exp?.Parameters);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override ISelect<T1, T2, T3> From<T2, T3>(
|
||||
Expression<Func<ISelectFromExpression<T1>, T2, T3, ISelectFromExpression<T1>>> exp)
|
||||
{
|
||||
this.InternalFrom(exp);
|
||||
var ret = new QuestDbSelect<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null);
|
||||
QuestDbSelect<T1>.CopyData(this, ret, exp?.Parameters);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override ISelect<T1, T2, T3, T4> From<T2, T3, T4>(
|
||||
Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, ISelectFromExpression<T1>>> exp)
|
||||
{
|
||||
this.InternalFrom(exp);
|
||||
var ret = new QuestDbSelect<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null);
|
||||
QuestDbSelect<T1>.CopyData(this, ret, exp?.Parameters);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override ISelect<T1, T2, T3, T4, T5> From<T2, T3, T4, T5>(
|
||||
Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, ISelectFromExpression<T1>>> exp)
|
||||
{
|
||||
this.InternalFrom(exp);
|
||||
var ret = new QuestDbSelect<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null);
|
||||
QuestDbSelect<T1>.CopyData(this, ret, exp?.Parameters);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override ISelect<T1, T2, T3, T4, T5, T6> From<T2, T3, T4, T5, T6>(
|
||||
Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, ISelectFromExpression<T1>>> exp)
|
||||
{
|
||||
this.InternalFrom(exp);
|
||||
var ret = new QuestDbSelect<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null);
|
||||
QuestDbSelect<T1>.CopyData(this, ret, exp?.Parameters);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override ISelect<T1, T2, T3, T4, T5, T6, T7> From<T2, T3, T4, T5, T6, T7>(
|
||||
Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, ISelectFromExpression<T1>>> exp)
|
||||
{
|
||||
this.InternalFrom(exp);
|
||||
var ret = new QuestDbSelect<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null);
|
||||
QuestDbSelect<T1>.CopyData(this, ret, exp?.Parameters);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8> From<T2, T3, T4, T5, T6, T7, T8>(
|
||||
Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression<T1>>> exp)
|
||||
{
|
||||
this.InternalFrom(exp);
|
||||
var ret = new QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null);
|
||||
QuestDbSelect<T1>.CopyData(this, ret, exp?.Parameters);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> From<T2, T3, T4, T5, T6, T7, T8, T9>(
|
||||
Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression<T1>>> exp)
|
||||
{
|
||||
this.InternalFrom(exp);
|
||||
var ret = new QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression,
|
||||
null);
|
||||
QuestDbSelect<T1>.CopyData(this, ret, exp?.Parameters);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> From<T2, T3, T4, T5, T6, T7, T8, T9, T10>(
|
||||
Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression<T1>>>
|
||||
exp)
|
||||
{
|
||||
this.InternalFrom(exp);
|
||||
var ret = new QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils,
|
||||
_commonExpression, null);
|
||||
QuestDbSelect<T1>.CopyData(this, ret, exp?.Parameters);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>
|
||||
From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(
|
||||
Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
|
||||
ISelectFromExpression<T1>>> exp)
|
||||
{
|
||||
this.InternalFrom(exp);
|
||||
var ret = new QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(_orm, _commonUtils,
|
||||
_commonExpression, null);
|
||||
QuestDbSelect<T1>.CopyData(this, ret, exp?.Parameters);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>
|
||||
From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(
|
||||
Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
|
||||
ISelectFromExpression<T1>>> exp)
|
||||
{
|
||||
this.InternalFrom(exp);
|
||||
var ret = new QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(_orm, _commonUtils,
|
||||
_commonExpression, null);
|
||||
QuestDbSelect<T1>.CopyData(this, ret, exp?.Parameters);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>
|
||||
From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(
|
||||
Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
|
||||
ISelectFromExpression<T1>>> exp)
|
||||
{
|
||||
this.InternalFrom(exp);
|
||||
var ret = new QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(_orm, _commonUtils,
|
||||
_commonExpression, null);
|
||||
QuestDbSelect<T1>.CopyData(this, ret, exp?.Parameters);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>
|
||||
From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(
|
||||
Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
|
||||
ISelectFromExpression<T1>>> exp)
|
||||
{
|
||||
this.InternalFrom(exp);
|
||||
var ret = new QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(_orm,
|
||||
_commonUtils, _commonExpression, null);
|
||||
QuestDbSelect<T1>.CopyData(this, ret, exp?.Parameters);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> From<T2, T3, T4, T5,
|
||||
T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(
|
||||
Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
|
||||
ISelectFromExpression<T1>>> exp)
|
||||
{
|
||||
this.InternalFrom(exp);
|
||||
var ret = new QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(_orm,
|
||||
_commonUtils, _commonExpression, null);
|
||||
QuestDbSelect<T1>.CopyData(this, ret, exp?.Parameters);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> From<T2, T3, T4,
|
||||
T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(
|
||||
Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16
|
||||
, ISelectFromExpression<T1>>> exp)
|
||||
{
|
||||
this.InternalFrom(exp);
|
||||
var ret = new QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(_orm,
|
||||
_commonUtils, _commonExpression, null);
|
||||
QuestDbSelect<T1>.CopyData(this, ret, exp?.Parameters);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override string ToSql(string field = null) => ToSqlStatic(_commonUtils, _commonExpression, _select,
|
||||
_distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having,
|
||||
_orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent,
|
||||
_whereGlobalFilter, _orm);
|
||||
}
|
||||
|
||||
class QuestDbSelect<T1, T2> : FreeSql.Internal.CommonProvider.Select2Provider<T1, T2> where T2 : class
|
||||
{
|
||||
public QuestDbSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression,
|
||||
object dywhere) : base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql(string field = null) => QuestDbSelect<T1>.ToSqlStatic(_commonUtils,
|
||||
_commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where,
|
||||
_groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule,
|
||||
_tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||
}
|
||||
|
||||
class QuestDbSelect<T1, T2, T3> : FreeSql.Internal.CommonProvider.Select3Provider<T1, T2, T3>
|
||||
where T2 : class where T3 : class
|
||||
{
|
||||
public QuestDbSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression,
|
||||
object dywhere) : base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql(string field = null) => QuestDbSelect<T1>.ToSqlStatic(_commonUtils,
|
||||
_commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where,
|
||||
_groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule,
|
||||
_tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||
}
|
||||
|
||||
class QuestDbSelect<T1, T2, T3, T4> : FreeSql.Internal.CommonProvider.Select4Provider<T1, T2, T3, T4>
|
||||
where T2 : class where T3 : class where T4 : class
|
||||
{
|
||||
public QuestDbSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression,
|
||||
object dywhere) : base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql(string field = null) => QuestDbSelect<T1>.ToSqlStatic(_commonUtils,
|
||||
_commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where,
|
||||
_groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule,
|
||||
_tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||
}
|
||||
|
||||
class QuestDbSelect<T1, T2, T3, T4, T5> : FreeSql.Internal.CommonProvider.Select5Provider<T1, T2, T3, T4, T5>
|
||||
where T2 : class where T3 : class where T4 : class where T5 : class
|
||||
{
|
||||
public QuestDbSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression,
|
||||
object dywhere) : base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql(string field = null) => QuestDbSelect<T1>.ToSqlStatic(_commonUtils,
|
||||
_commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where,
|
||||
_groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule,
|
||||
_tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||
}
|
||||
|
||||
class QuestDbSelect<T1, T2, T3, T4, T5, T6> : FreeSql.Internal.CommonProvider.Select6Provider<T1, T2, T3, T4, T5,
|
||||
T6> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class
|
||||
{
|
||||
public QuestDbSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression,
|
||||
object dywhere) : base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql(string field = null) => QuestDbSelect<T1>.ToSqlStatic(_commonUtils,
|
||||
_commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where,
|
||||
_groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule,
|
||||
_tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||
}
|
||||
|
||||
class QuestDbSelect<T1, T2, T3, T4, T5, T6, T7> : FreeSql.Internal.CommonProvider.Select7Provider<T1, T2, T3, T4,
|
||||
T5, T6, T7> where T2 : class
|
||||
where T3 : class
|
||||
where T4 : class
|
||||
where T5 : class
|
||||
where T6 : class
|
||||
where T7 : class
|
||||
{
|
||||
public QuestDbSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression,
|
||||
object dywhere) : base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql(string field = null) => QuestDbSelect<T1>.ToSqlStatic(_commonUtils,
|
||||
_commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where,
|
||||
_groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule,
|
||||
_tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||
}
|
||||
|
||||
class QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8> : FreeSql.Internal.CommonProvider.Select8Provider<T1, T2, T3,
|
||||
T4, T5, T6, T7, T8> where T2 : class
|
||||
where T3 : class
|
||||
where T4 : class
|
||||
where T5 : class
|
||||
where T6 : class
|
||||
where T7 : class
|
||||
where T8 : class
|
||||
{
|
||||
public QuestDbSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression,
|
||||
object dywhere) : base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql(string field = null) => QuestDbSelect<T1>.ToSqlStatic(_commonUtils,
|
||||
_commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where,
|
||||
_groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule,
|
||||
_tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||
}
|
||||
|
||||
class QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> : FreeSql.Internal.CommonProvider.Select9Provider<T1, T2,
|
||||
T3, T4, T5, T6, T7, T8, T9> where T2 : class
|
||||
where T3 : class
|
||||
where T4 : class
|
||||
where T5 : class
|
||||
where T6 : class
|
||||
where T7 : class
|
||||
where T8 : class
|
||||
where T9 : class
|
||||
{
|
||||
public QuestDbSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression,
|
||||
object dywhere) : base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql(string field = null) => QuestDbSelect<T1>.ToSqlStatic(_commonUtils,
|
||||
_commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where,
|
||||
_groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule,
|
||||
_tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||
}
|
||||
|
||||
class QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : FreeSql.Internal.CommonProvider.Select10Provider<
|
||||
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> where T2 : class
|
||||
where T3 : class
|
||||
where T4 : class
|
||||
where T5 : class
|
||||
where T6 : class
|
||||
where T7 : class
|
||||
where T8 : class
|
||||
where T9 : class
|
||||
where T10 : class
|
||||
{
|
||||
public QuestDbSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression,
|
||||
object dywhere) : base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql(string field = null) => QuestDbSelect<T1>.ToSqlStatic(_commonUtils,
|
||||
_commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where,
|
||||
_groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule,
|
||||
_tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||
}
|
||||
|
||||
class QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> : FreeSql.Internal.CommonProvider.
|
||||
Select11Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> where T2 : class
|
||||
where T3 : class
|
||||
where T4 : class
|
||||
where T5 : class
|
||||
where T6 : class
|
||||
where T7 : class
|
||||
where T8 : class
|
||||
where T9 : class
|
||||
where T10 : class
|
||||
where T11 : class
|
||||
{
|
||||
public QuestDbSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression,
|
||||
object dywhere) : base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql(string field = null) => QuestDbSelect<T1>.ToSqlStatic(_commonUtils,
|
||||
_commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where,
|
||||
_groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule,
|
||||
_tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||
}
|
||||
|
||||
class QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> : FreeSql.Internal.CommonProvider.
|
||||
Select12Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> where T2 : class
|
||||
where T3 : class
|
||||
where T4 : class
|
||||
where T5 : class
|
||||
where T6 : class
|
||||
where T7 : class
|
||||
where T8 : class
|
||||
where T9 : class
|
||||
where T10 : class
|
||||
where T11 : class
|
||||
where T12 : class
|
||||
{
|
||||
public QuestDbSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression,
|
||||
object dywhere) : base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql(string field = null) => QuestDbSelect<T1>.ToSqlStatic(_commonUtils,
|
||||
_commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where,
|
||||
_groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule,
|
||||
_tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||
}
|
||||
|
||||
class QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> : FreeSql.Internal.CommonProvider.
|
||||
Select13Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> where T2 : class
|
||||
where T3 : class
|
||||
where T4 : class
|
||||
where T5 : class
|
||||
where T6 : class
|
||||
where T7 : class
|
||||
where T8 : class
|
||||
where T9 : class
|
||||
where T10 : class
|
||||
where T11 : class
|
||||
where T12 : class
|
||||
where T13 : class
|
||||
{
|
||||
public QuestDbSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression,
|
||||
object dywhere) : base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql(string field = null) => QuestDbSelect<T1>.ToSqlStatic(_commonUtils,
|
||||
_commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where,
|
||||
_groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule,
|
||||
_tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||
}
|
||||
|
||||
class QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> : FreeSql.Internal.
|
||||
CommonProvider.Select14Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> where T2 : class
|
||||
where T3 : class
|
||||
where T4 : class
|
||||
where T5 : class
|
||||
where T6 : class
|
||||
where T7 : class
|
||||
where T8 : class
|
||||
where T9 : class
|
||||
where T10 : class
|
||||
where T11 : class
|
||||
where T12 : class
|
||||
where T13 : class
|
||||
where T14 : class
|
||||
{
|
||||
public QuestDbSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression,
|
||||
object dywhere) : base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql(string field = null) => QuestDbSelect<T1>.ToSqlStatic(_commonUtils,
|
||||
_commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where,
|
||||
_groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule,
|
||||
_tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||
}
|
||||
|
||||
class QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> : FreeSql.Internal.
|
||||
CommonProvider.Select15Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>
|
||||
where T2 : class
|
||||
where T3 : class
|
||||
where T4 : class
|
||||
where T5 : class
|
||||
where T6 : class
|
||||
where T7 : class
|
||||
where T8 : class
|
||||
where T9 : class
|
||||
where T10 : class
|
||||
where T11 : class
|
||||
where T12 : class
|
||||
where T13 : class
|
||||
where T14 : class
|
||||
where T15 : class
|
||||
{
|
||||
public QuestDbSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression,
|
||||
object dywhere) : base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql(string field = null) => QuestDbSelect<T1>.ToSqlStatic(_commonUtils,
|
||||
_commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where,
|
||||
_groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule,
|
||||
_tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||
}
|
||||
|
||||
class QuestDbSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> : FreeSql.Internal.
|
||||
CommonProvider.Select16Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>
|
||||
where T2 : class
|
||||
where T3 : class
|
||||
where T4 : class
|
||||
where T5 : class
|
||||
where T6 : class
|
||||
where T7 : class
|
||||
where T8 : class
|
||||
where T9 : class
|
||||
where T10 : class
|
||||
where T11 : class
|
||||
where T12 : class
|
||||
where T13 : class
|
||||
where T14 : class
|
||||
where T15 : class
|
||||
where T16 : class
|
||||
{
|
||||
public QuestDbSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression,
|
||||
object dywhere) : base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToSql(string field = null) => QuestDbSelect<T1>.ToSqlStatic(_commonUtils,
|
||||
_commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where,
|
||||
_groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule,
|
||||
_tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||
}
|
||||
}
|
244
Providers/FreeSql.Provider.QuestDb/Curd/QuestDbUpdate.cs
Normal file
244
Providers/FreeSql.Provider.QuestDb/Curd/QuestDbUpdate.cs
Normal file
@ -0,0 +1,244 @@
|
||||
using FreeSql.Internal;
|
||||
using FreeSql.Internal.Model;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FreeSql.QuestDb.Curd
|
||||
{
|
||||
class QuestDbUpdate<T1> : Internal.CommonProvider.UpdateProvider<T1>
|
||||
{
|
||||
public QuestDbUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
|
||||
: base(orm, commonUtils, commonExpression, dywhere)
|
||||
{
|
||||
}
|
||||
|
||||
internal string InternalTableAlias { get; set; }
|
||||
internal StringBuilder InternalSbSet => _set;
|
||||
internal StringBuilder InternalSbSetIncr => _setIncr;
|
||||
internal Dictionary<string, bool> InternalIgnore => _ignore;
|
||||
internal void InternalResetSource(List<T1> source) => _source = source;
|
||||
|
||||
internal string InternalWhereCaseSource(string CsName, Func<string, string> thenValue) =>
|
||||
WhereCaseSource(CsName, thenValue);
|
||||
|
||||
internal void InternalToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col) => ToSqlCaseWhenEnd(sb, col);
|
||||
|
||||
private int InternelExecuteAffrows()
|
||||
{
|
||||
var sql = ToSql();
|
||||
var execAsync = RestAPIExtension.ExecAsync(sql).GetAwaiter().GetResult();
|
||||
var resultHash = new Hashtable();
|
||||
try
|
||||
{
|
||||
resultHash = JsonConvert.DeserializeObject<Hashtable>(execAsync);
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (execAsync.Contains("401"))
|
||||
{
|
||||
throw new Exception("请确认new FreeSqlBuilder().UseQuestDbRestAPI()中设置的用户名密码是否正确.");
|
||||
}
|
||||
}
|
||||
var ddl = resultHash["ddl"]?.ToString();
|
||||
var updated = Convert.ToInt32(resultHash["updated"]);
|
||||
return ddl?.ToLower() == "ok" ? updated : 0;
|
||||
}
|
||||
|
||||
public override int ExecuteAffrows()
|
||||
{
|
||||
//如果设置了RestAPI中Url则走HTTP
|
||||
if (string.IsNullOrWhiteSpace(RestAPIExtension.BaseUrl))
|
||||
{
|
||||
return base.SplitExecuteAffrows(_batchRowsLimit > 0 ? _batchRowsLimit : 500,
|
||||
_batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||
}
|
||||
return InternelExecuteAffrows();
|
||||
}
|
||||
|
||||
protected override List<TReturn> ExecuteUpdated<TReturn>(IEnumerable<ColumnInfo> columns) => base.SplitExecuteUpdated<TReturn>(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, columns);
|
||||
|
||||
protected override List<TReturn> RawExecuteUpdated<TReturn>(IEnumerable<ColumnInfo> columns)
|
||||
{
|
||||
var ret = new List<TReturn>();
|
||||
DbParameter[] dbParms = null;
|
||||
StringBuilder sbret = null;
|
||||
ToSqlFetch(sb =>
|
||||
{
|
||||
if (dbParms == null)
|
||||
{
|
||||
dbParms = _params.Concat(_paramsSource).ToArray();
|
||||
sbret = new StringBuilder();
|
||||
sbret.Append(" RETURNING ");
|
||||
|
||||
var colidx = 0;
|
||||
foreach (var col in columns)
|
||||
{
|
||||
if (colidx > 0) sbret.Append(", ");
|
||||
sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name)))
|
||||
.Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||
++colidx;
|
||||
}
|
||||
}
|
||||
|
||||
var sql = sb.Append(sbret).ToString();
|
||||
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Update, sql, dbParms);
|
||||
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
var queryType = typeof(TReturn) == typeof(T1) ? (_table.TypeLazy ?? _table.Type) : null;
|
||||
var rettmp = _orm.Ado.Query<TReturn>(queryType, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms);
|
||||
ValidateVersionAndThrow(rettmp.Count, sql, dbParms);
|
||||
ret.AddRange(rettmp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
|
||||
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||
}
|
||||
});
|
||||
sbret?.Clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys)
|
||||
{
|
||||
if (primarys.Length == 1)
|
||||
{
|
||||
var pk = primarys.First();
|
||||
if (string.IsNullOrEmpty(InternalTableAlias) == false) caseWhen.Append(InternalTableAlias).Append(".");
|
||||
caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
|
||||
return;
|
||||
}
|
||||
|
||||
caseWhen.Append("(");
|
||||
var pkidx = 0;
|
||||
foreach (var pk in primarys)
|
||||
{
|
||||
if (pkidx > 0) caseWhen.Append(" || '+' || ");
|
||||
if (string.IsNullOrEmpty(InternalTableAlias) == false) caseWhen.Append(InternalTableAlias).Append(".");
|
||||
caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name)))
|
||||
.Append("::text");
|
||||
++pkidx;
|
||||
}
|
||||
|
||||
caseWhen.Append(")");
|
||||
}
|
||||
|
||||
protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d)
|
||||
{
|
||||
if (primarys.Length == 1)
|
||||
{
|
||||
sb.Append(_commonUtils.FormatSql("{0}", primarys[0].GetDbValue(d)));
|
||||
return;
|
||||
}
|
||||
|
||||
sb.Append("(");
|
||||
var pkidx = 0;
|
||||
foreach (var pk in primarys)
|
||||
{
|
||||
if (pkidx > 0) sb.Append(" || '+' || ");
|
||||
sb.Append(_commonUtils.FormatSql("{0}", pk.GetDbValue(d))).Append("::text");
|
||||
++pkidx;
|
||||
}
|
||||
|
||||
sb.Append(")");
|
||||
}
|
||||
|
||||
protected override void ToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col)
|
||||
{
|
||||
if (_noneParameter == false) return;
|
||||
if (col.Attribute.MapType == typeof(string))
|
||||
{
|
||||
sb.Append("::text");
|
||||
return;
|
||||
}
|
||||
|
||||
var dbtype = _commonUtils.CodeFirst.GetDbInfo(col.Attribute.MapType)?.dbtype;
|
||||
if (dbtype == null) return;
|
||||
|
||||
sb.Append("::").Append(dbtype);
|
||||
}
|
||||
|
||||
#if net40
|
||||
#else
|
||||
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(RestAPIExtension.BaseUrl))
|
||||
{
|
||||
return base.SplitExecuteAffrowsAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 500,
|
||||
_batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
|
||||
}
|
||||
|
||||
return Task.FromResult(InternelExecuteAffrows());
|
||||
}
|
||||
|
||||
|
||||
protected override Task<List<TReturn>> ExecuteUpdatedAsync<TReturn>(IEnumerable<ColumnInfo> columns, CancellationToken cancellationToken = default) => base.SplitExecuteUpdatedAsync<TReturn>(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, columns, cancellationToken);
|
||||
|
||||
async protected override Task<List<TReturn>> RawExecuteUpdatedAsync<TReturn>(IEnumerable<ColumnInfo> columns, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var ret = new List<TReturn>();
|
||||
DbParameter[] dbParms = null;
|
||||
StringBuilder sbret = null;
|
||||
await ToSqlFetchAsync(async sb =>
|
||||
{
|
||||
if (dbParms == null)
|
||||
{
|
||||
dbParms = _params.Concat(_paramsSource).ToArray();
|
||||
sbret = new StringBuilder();
|
||||
sbret.Append(" RETURNING ");
|
||||
|
||||
var colidx = 0;
|
||||
foreach (var col in columns)
|
||||
{
|
||||
if (colidx > 0) sbret.Append(", ");
|
||||
sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name)))
|
||||
.Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||
++colidx;
|
||||
}
|
||||
}
|
||||
|
||||
var sql = sb.Append(sbret).ToString();
|
||||
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Update, sql, dbParms);
|
||||
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
var queryType = typeof(TReturn) == typeof(T1) ? (_table.TypeLazy ?? _table.Type) : null;
|
||||
var rettmp = await _orm.Ado.QueryAsync<TReturn>(queryType, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken);
|
||||
ValidateVersionAndThrow(rettmp.Count, sql, dbParms);
|
||||
ret.AddRange(rettmp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
|
||||
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||
}
|
||||
});
|
||||
sbret?.Clear();
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;</TargetFrameworks>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Authors>YeXiangQin;Daily</Authors>
|
||||
<Description>FreeSql 实现 QuestDB 时序数据库访问</Description>
|
||||
<PackageProjectUrl>https://github.com/2881099/FreeSql</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/2881099/FreeSql</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageTags>FreeSql;ORM;QuestDb</PackageTags>
|
||||
<PackageId>$(AssemblyName)</PackageId>
|
||||
<PackageIcon>logo.png</PackageIcon>
|
||||
<Title>$(AssemblyName)</Title>
|
||||
<IsPackable>true</IsPackable>
|
||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
|
||||
<DelaySign>false</DelaySign>
|
||||
<Version>3.2.833</Version>
|
||||
<PackageReadmeFile>readme.md</PackageReadmeFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="../../readme.md" Pack="true" PackagePath="\"/>
|
||||
<None Include="../../logo.png" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.32" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
||||
<PackageReference Include="Npgsql" Version="5.0.11" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
121
Providers/FreeSql.Provider.QuestDb/QuestDbAdo/QuestDbAdo.cs
Normal file
121
Providers/FreeSql.Provider.QuestDb/QuestDbAdo/QuestDbAdo.cs
Normal file
@ -0,0 +1,121 @@
|
||||
using FreeSql.Internal;
|
||||
using FreeSql.Internal.CommonProvider;
|
||||
using FreeSql.Internal.Model;
|
||||
using FreeSql.Internal.ObjectPool;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Npgsql;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace FreeSql.QuestDb
|
||||
{
|
||||
class QuestDbAdo : FreeSql.Internal.CommonProvider.AdoProvider
|
||||
{
|
||||
public QuestDbAdo() : base(DataType.QuestDb, null, null) { }
|
||||
public QuestDbAdo(CommonUtils util, string masterConnectionString, string[] slaveConnectionStrings, Func<DbConnection> connectionFactory) : base(DataType.QuestDb, masterConnectionString, slaveConnectionStrings)
|
||||
{
|
||||
base._util = util;
|
||||
if (connectionFactory != null)
|
||||
{
|
||||
var pool = new FreeSql.Internal.CommonProvider.DbConnectionPool(DataType.QuestDb, connectionFactory);
|
||||
ConnectionString = pool.TestConnection?.ConnectionString;
|
||||
MasterPool = pool;
|
||||
return;
|
||||
}
|
||||
|
||||
var isAdoPool = masterConnectionString?.StartsWith("AdoConnectionPool,") ?? false;
|
||||
if (isAdoPool) masterConnectionString = masterConnectionString.Substring("AdoConnectionPool,".Length);
|
||||
if (!string.IsNullOrEmpty(masterConnectionString))
|
||||
MasterPool = isAdoPool ?
|
||||
new DbConnectionStringPool(base.DataType, CoreStrings.S_MasterDatabase, () => new NpgsqlConnection(masterConnectionString)) as IObjectPool<DbConnection> :
|
||||
new QuestDbConnectionPool(CoreStrings.S_MasterDatabase, masterConnectionString, null, null);
|
||||
|
||||
slaveConnectionStrings?.ToList().ForEach(slaveConnectionString =>
|
||||
{
|
||||
var slavePool = isAdoPool ?
|
||||
new DbConnectionStringPool(base.DataType, $"{CoreStrings.S_SlaveDatabase}{SlavePools.Count + 1}", () => new NpgsqlConnection(slaveConnectionString)) as IObjectPool<DbConnection> :
|
||||
new QuestDbConnectionPool($"{CoreStrings.S_SlaveDatabase}{SlavePools.Count + 1}", slaveConnectionString, () => Interlocked.Decrement(ref slaveUnavailables), () => Interlocked.Increment(ref slaveUnavailables));
|
||||
SlavePools.Add(slavePool);
|
||||
});
|
||||
}
|
||||
|
||||
public override object AddslashesProcessParam(object param, Type mapType, ColumnInfo mapColumn)
|
||||
{
|
||||
if (param == null) return "NULL";
|
||||
if (mapType != null && mapType != param.GetType() && (param is IEnumerable == false || param is JToken || param is JObject || param is JArray))
|
||||
param = Utils.GetDataReaderValue(mapType, param);
|
||||
|
||||
bool isdic;
|
||||
if (param is bool || param is bool?)
|
||||
return (bool)param ? "true" : "false";
|
||||
else if (param is string)
|
||||
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
|
||||
else if (param is Guid || param is Guid?)
|
||||
return string.Concat("'", ((Guid)param).ToString("n"), "'");
|
||||
else if (param is char)
|
||||
return string.Concat("'", param.ToString().Replace("'", "''").Replace('\0', ' '), "'");
|
||||
else if (param is Enum)
|
||||
return AddslashesTypeHandler(param.GetType(), param) ?? ((Enum)param).ToInt64();
|
||||
else if (decimal.TryParse(string.Concat(param), out var trydec))
|
||||
return param;
|
||||
|
||||
else if (param is DateTime)
|
||||
return AddslashesTypeHandler(typeof(DateTime), param) ?? string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "'");
|
||||
else if (param is DateTime?)
|
||||
return AddslashesTypeHandler(typeof(DateTime?), param) ?? string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "'");
|
||||
|
||||
else if (param is TimeSpan || param is TimeSpan?)
|
||||
return (long)((TimeSpan)param).TotalSeconds;
|
||||
else if (param is byte[])
|
||||
return $"'\\x{CommonUtils.BytesSqlRaw(param as byte[])}'";
|
||||
else if (param is JToken || param is JObject || param is JArray)
|
||||
return string.Concat("'", param.ToString().Replace("'", "''"), "'::jsonb");
|
||||
else if ((isdic = param is Dictionary<string, string>) ||
|
||||
param is IEnumerable<KeyValuePair<string, string>>)
|
||||
{
|
||||
var pgdics = isdic ? param as Dictionary<string, string> :
|
||||
param as IEnumerable<KeyValuePair<string, string>>;
|
||||
|
||||
var pghstore = new StringBuilder("'");
|
||||
var pairs = pgdics.ToArray();
|
||||
|
||||
for (var i = 0; i < pairs.Length; i++)
|
||||
{
|
||||
if (i != 0) pghstore.Append(",");
|
||||
|
||||
pghstore.AppendFormat("\"{0}\"=>", pairs[i].Key.Replace("'", "''"));
|
||||
|
||||
if (pairs[i].Value == null)
|
||||
pghstore.Append("NULL");
|
||||
else
|
||||
pghstore.AppendFormat("\"{0}\"", pairs[i].Value.Replace("'", "''"));
|
||||
}
|
||||
|
||||
return pghstore.Append("'::hstore");
|
||||
}
|
||||
else if (param is IEnumerable)
|
||||
return AddslashesIEnumerable(param, mapType, mapColumn);
|
||||
|
||||
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
|
||||
}
|
||||
|
||||
public override DbCommand CreateCommand()
|
||||
{
|
||||
return new NpgsqlCommand();
|
||||
}
|
||||
|
||||
public override void ReturnConnection(IObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex)
|
||||
{
|
||||
var rawPool = pool as QuestDbConnectionPool;
|
||||
if (rawPool != null) rawPool.Return(conn, ex);
|
||||
else pool.Return(conn);
|
||||
}
|
||||
|
||||
public override DbParameter[] GetDbParamtersByObject(string sql, object obj) => _util.GetDbParamtersByObject(sql, obj);
|
||||
}
|
||||
}
|
@ -0,0 +1,241 @@
|
||||
using Npgsql;
|
||||
using FreeSql.Internal.ObjectPool;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FreeSql.QuestDb
|
||||
{
|
||||
|
||||
class QuestDbConnectionPool : ObjectPool<DbConnection>
|
||||
{
|
||||
|
||||
internal Action availableHandler;
|
||||
internal Action unavailableHandler;
|
||||
|
||||
public QuestDbConnectionPool(string name, string connectionString, Action availableHandler, Action unavailableHandler) : base(null)
|
||||
{
|
||||
this.availableHandler = availableHandler;
|
||||
this.unavailableHandler = unavailableHandler;
|
||||
var policy = new QuestDbConnectionPoolPolicy
|
||||
{
|
||||
_pool = this,
|
||||
Name = name
|
||||
};
|
||||
this.Policy = policy;
|
||||
policy.ConnectionString = connectionString;
|
||||
}
|
||||
|
||||
public void Return(Object<DbConnection> obj, Exception exception, bool isRecreate = false)
|
||||
{
|
||||
if (exception != null && exception is NpgsqlException)
|
||||
{
|
||||
if (obj.Value.Ping() == false)
|
||||
base.SetUnavailable(exception, obj.LastGetTimeCopy);
|
||||
}
|
||||
base.Return(obj, isRecreate);
|
||||
}
|
||||
}
|
||||
|
||||
class QuestDbConnectionPoolPolicy : IPolicy<DbConnection>
|
||||
{
|
||||
|
||||
internal QuestDbConnectionPool _pool;
|
||||
public string Name { get; set; } = $"QuestDb NpgsqlConnection {CoreStrings.S_ObjectPool}";
|
||||
public int PoolSize { get; set; } = 50;
|
||||
public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10);
|
||||
public TimeSpan IdleTimeout { get; set; } = TimeSpan.FromSeconds(20);
|
||||
public int AsyncGetCapacity { get; set; } = 10000;
|
||||
public bool IsThrowGetTimeoutException { get; set; } = true;
|
||||
public bool IsAutoDisposeWithSystem { get; set; } = true;
|
||||
public int CheckAvailableInterval { get; set; } = 2;
|
||||
public int Weight { get; set; } = 1;
|
||||
|
||||
static ConcurrentDictionary<string, int> dicConnStrIncr = new ConcurrentDictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
|
||||
private string _connectionString;
|
||||
public string ConnectionString
|
||||
{
|
||||
get => _connectionString;
|
||||
set
|
||||
{
|
||||
_connectionString = value ?? "";
|
||||
|
||||
var minPoolSize = 0;
|
||||
var pattern = @"Min(imum)?\s*pool\s*size\s*=\s*(\d+)";
|
||||
var m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
|
||||
if (m.Success)
|
||||
{
|
||||
minPoolSize = int.Parse(m.Groups[2].Value);
|
||||
_connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
pattern = @"Max(imum)?\s*pool\s*size\s*=\s*(\d+)";
|
||||
m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
|
||||
if (m.Success == false || int.TryParse(m.Groups[2].Value, out var poolsize) == false || poolsize <= 0) poolsize = Math.Max(50, minPoolSize);
|
||||
var connStrIncr = dicConnStrIncr.AddOrUpdate(_connectionString, 1, (oldkey, oldval) => Math.Min(5, oldval + 1));
|
||||
PoolSize = poolsize + connStrIncr;
|
||||
_connectionString = m.Success ?
|
||||
Regex.Replace(_connectionString, pattern, $"Maximum pool size={PoolSize}", RegexOptions.IgnoreCase) :
|
||||
$"{_connectionString};Maximum pool size={PoolSize}";
|
||||
|
||||
pattern = @"Connection\s*LifeTime\s*=\s*(\d+)";
|
||||
m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
|
||||
if (m.Success)
|
||||
{
|
||||
IdleTimeout = TimeSpan.FromSeconds(int.Parse(m.Groups[1].Value));
|
||||
_connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
FreeSql.Internal.CommonUtils.PrevReheatConnectionPool(_pool, minPoolSize);
|
||||
}
|
||||
}
|
||||
|
||||
public bool OnCheckAvailable(Object<DbConnection> obj)
|
||||
{
|
||||
if (obj.Value == null) return false;
|
||||
if (obj.Value.State == ConnectionState.Closed) obj.Value.Open();
|
||||
return obj.Value.Ping(true);
|
||||
}
|
||||
|
||||
public DbConnection OnCreate()
|
||||
{
|
||||
var conn = new NpgsqlConnection(_connectionString);
|
||||
return conn;
|
||||
}
|
||||
|
||||
public void OnDestroy(DbConnection obj)
|
||||
{
|
||||
try { if (obj.State != ConnectionState.Closed) obj.Close(); } catch { }
|
||||
try { NpgsqlConnection.ClearPool(obj as NpgsqlConnection); } catch { }
|
||||
obj.Dispose();
|
||||
}
|
||||
|
||||
public void OnGet(Object<DbConnection> obj)
|
||||
{
|
||||
|
||||
if (_pool.IsAvailable)
|
||||
{
|
||||
if (obj.Value == null)
|
||||
{
|
||||
_pool.SetUnavailable(new Exception(CoreStrings.S_ConnectionStringError), obj.LastGetTimeCopy);
|
||||
throw new Exception(CoreStrings.S_ConnectionStringError_Check(this.Name));
|
||||
}
|
||||
|
||||
if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && obj.Value.Ping() == false)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
obj.Value.Open();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (_pool.SetUnavailable(ex, obj.LastGetTimeCopy) == true)
|
||||
throw new Exception($"【{this.Name}】Block access and wait for recovery: {ex.Message}");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if net40
|
||||
#else
|
||||
async public Task OnGetAsync(Object<DbConnection> obj)
|
||||
{
|
||||
|
||||
if (_pool.IsAvailable)
|
||||
{
|
||||
if (obj.Value == null)
|
||||
{
|
||||
_pool.SetUnavailable(new Exception(CoreStrings.S_ConnectionStringError), obj.LastGetTimeCopy);
|
||||
throw new Exception(CoreStrings.S_ConnectionStringError_Check(this.Name));
|
||||
}
|
||||
|
||||
if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && (await obj.Value.PingAsync()) == false)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
await obj.Value.OpenAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (_pool.SetUnavailable(ex, obj.LastGetTimeCopy) == true)
|
||||
throw new Exception($"【{this.Name}】Block access and wait for recovery: {ex.Message}");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public void OnGetTimeout()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnReturn(Object<DbConnection> obj)
|
||||
{
|
||||
//if (obj?.Value != null && obj.Value.State != ConnectionState.Closed) try { obj.Value.Close(); } catch { }
|
||||
}
|
||||
|
||||
public void OnAvailable()
|
||||
{
|
||||
_pool.availableHandler?.Invoke();
|
||||
}
|
||||
|
||||
public void OnUnavailable()
|
||||
{
|
||||
_pool.unavailableHandler?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
static class DbConnectionExtensions
|
||||
{
|
||||
|
||||
static DbCommand PingCommand(DbConnection conn)
|
||||
{
|
||||
var cmd = conn.CreateCommand();
|
||||
cmd.CommandTimeout = 5;
|
||||
cmd.CommandText = "select 1";
|
||||
return cmd;
|
||||
}
|
||||
public static bool Ping(this DbConnection that, bool isThrow = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
PingCommand(that).ExecuteNonQuery();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (that.State != ConnectionState.Closed) try { that.Close(); } catch { }
|
||||
if (isThrow) throw;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#if net40
|
||||
#else
|
||||
async public static Task<bool> PingAsync(this DbConnection that, bool isThrow = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
await PingCommand(that).ExecuteNonQueryAsync();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (that.State != ConnectionState.Closed) try { that.Close(); } catch { }
|
||||
if (isThrow) throw;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
254
Providers/FreeSql.Provider.QuestDb/QuestDbCodeFirst.cs
Normal file
254
Providers/FreeSql.Provider.QuestDb/QuestDbCodeFirst.cs
Normal file
@ -0,0 +1,254 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using FreeSql.Internal;
|
||||
using FreeSql.Internal.Model;
|
||||
using FreeSql.Provider.QuestDb.Subtable;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NpgsqlTypes;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace FreeSql.QuestDb
|
||||
{
|
||||
class QuestDbCodeFirst : Internal.CommonProvider.CodeFirstProvider
|
||||
{
|
||||
public QuestDbCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm,
|
||||
commonUtils, commonExpression)
|
||||
{
|
||||
}
|
||||
|
||||
static object _dicCsToDbLock = new object();
|
||||
|
||||
static Dictionary<string, CsToDb<NpgsqlDbType>> _dicCsToDb = new Dictionary<string, CsToDb<NpgsqlDbType>>()
|
||||
{
|
||||
{ typeof(sbyte).FullName, CsToDb.New(NpgsqlDbType.Smallint, "byte", "byte NOT NULL", false, false, 0) },
|
||||
{ typeof(sbyte?).FullName, CsToDb.New(NpgsqlDbType.Smallint, "byte", "byte", false, true, null) },
|
||||
{ typeof(short).FullName, CsToDb.New(NpgsqlDbType.Smallint, "short", "short NOT NULL", false, false, 0) },
|
||||
{ typeof(short?).FullName, CsToDb.New(NpgsqlDbType.Smallint, "short", "short", false, true, null) },
|
||||
{ typeof(int).FullName, CsToDb.New(NpgsqlDbType.Integer, "int", "int NOT NULL", false, false, 0) },
|
||||
{ typeof(int?).FullName, CsToDb.New(NpgsqlDbType.Integer, "int", "int", false, true, null) },
|
||||
{ typeof(long).FullName, CsToDb.New(NpgsqlDbType.Bigint, "long", "long NOT NULL", false, false, 0) },
|
||||
{ typeof(long?).FullName, CsToDb.New(NpgsqlDbType.Bigint, "long", "long", false, true, null) },
|
||||
|
||||
{ typeof(byte).FullName, CsToDb.New(NpgsqlDbType.Smallint, "byte", "byte NOT NULL", false, false, 0) },
|
||||
{ typeof(byte?).FullName, CsToDb.New(NpgsqlDbType.Smallint, "byte", "byte", false, true, null) },
|
||||
{ typeof(ushort).FullName, CsToDb.New(NpgsqlDbType.Integer, "short", "short NOT NULL", false, false, 0) },
|
||||
{ typeof(ushort?).FullName, CsToDb.New(NpgsqlDbType.Integer, "short", "short", false, true, null) },
|
||||
{ typeof(uint).FullName, CsToDb.New(NpgsqlDbType.Bigint, "int", "int NOT NULL", false, false, 0) },
|
||||
{ typeof(uint?).FullName, CsToDb.New(NpgsqlDbType.Bigint, "int", "int", false, true, null) },
|
||||
{ typeof(ulong).FullName, CsToDb.New(NpgsqlDbType.Numeric, "long", "long NOT NULL", false, false, 0) },
|
||||
{ typeof(ulong?).FullName, CsToDb.New(NpgsqlDbType.Numeric, "long", "long", false, true, null) },
|
||||
|
||||
{ typeof(float).FullName, CsToDb.New(NpgsqlDbType.Real, "float", "float NOT NULL", false, false, 0) },
|
||||
{ typeof(float?).FullName, CsToDb.New(NpgsqlDbType.Real, "float", "float", false, true, null) },
|
||||
{ typeof(double).FullName, CsToDb.New(NpgsqlDbType.Double, "double", "double NOT NULL", false, false, 0) },
|
||||
{ typeof(double?).FullName, CsToDb.New(NpgsqlDbType.Double, "double", "double", false, true, null) },
|
||||
{ typeof(decimal).FullName, CsToDb.New(NpgsqlDbType.Numeric, "double", "double NOT NULL", false, false, 0) },
|
||||
{ typeof(decimal?).FullName, CsToDb.New(NpgsqlDbType.Numeric, "double", "double", false, true, null) },
|
||||
|
||||
{ typeof(string).FullName, CsToDb.New(NpgsqlDbType.Varchar, "string", "string", false, null, "") },
|
||||
{ typeof(char).FullName, CsToDb.New(NpgsqlDbType.Char, "char", "char", false, null, '\0') },
|
||||
{ typeof(Guid).FullName, CsToDb.New(NpgsqlDbType.Char, "symbol", "symbol", false, null, Guid.Empty) },
|
||||
{ typeof(Guid?).FullName, CsToDb.New(NpgsqlDbType.Char, "symbol", "symbol", false, true, null) },
|
||||
|
||||
{ typeof(DateTime).FullName, CsToDb.New(NpgsqlDbType.Timestamp, "timestamp", "timestamp NOT NULL", false, false, new DateTime(1970, 1, 1)) },
|
||||
{ typeof(DateTime?).FullName, CsToDb.New(NpgsqlDbType.Timestamp, "timestamp", "timestamp", false, true, null) },
|
||||
|
||||
{ typeof(bool).FullName, CsToDb.New(NpgsqlDbType.Boolean, "boolean", "boolean NOT NULL", null, false, false) },
|
||||
{ typeof(bool?).FullName, CsToDb.New(NpgsqlDbType.Boolean, "boolean", "boolean", null, true, null) },
|
||||
{ typeof(Byte[]).FullName, CsToDb.New(NpgsqlDbType.Bytea, "binary", "binary", false, null, new byte[0]) },
|
||||
{ typeof(BigInteger).FullName, CsToDb.New(NpgsqlDbType.Numeric, "long256", "long256 NOT NULL", false, false, 0) },
|
||||
{ typeof(BigInteger?).FullName, CsToDb.New(NpgsqlDbType.Numeric, "long256", "long256", false, true, null) }
|
||||
};
|
||||
|
||||
public override DbInfoResult GetDbInfo(Type type)
|
||||
{
|
||||
if (_dicCsToDb.TryGetValue(type.FullName, out var trydc))
|
||||
return new DbInfoResult((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable,
|
||||
trydc.defaultValue);
|
||||
if (type.IsArray)
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override string GetComparisonDDLStatements(params TypeSchemaAndName[] objects)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var seqcols = new List<NativeTuple<ColumnInfo, string[], bool>>(); //序列
|
||||
|
||||
foreach (var obj in objects)
|
||||
{
|
||||
if (sb.Length > 0) sb.Append("\r\n");
|
||||
var tb = obj.tableSchema;
|
||||
if (tb == null) throw new Exception(CoreStrings.S_Type_IsNot_Migrable(obj.tableSchema.Type.FullName));
|
||||
if (tb.Columns.Any() == false)
|
||||
throw new Exception(CoreStrings.S_Type_IsNot_Migrable_0Attributes(obj.tableSchema.Type.FullName));
|
||||
var tbname = tb.DbName;
|
||||
var tboldname = tb.DbOldName;
|
||||
if (string.IsNullOrEmpty(obj.tableName) == false)
|
||||
{
|
||||
var tbtmpname = obj.tableName;
|
||||
if (tbname != tbtmpname)
|
||||
{
|
||||
tbname = tbtmpname;
|
||||
tboldname = null;
|
||||
}
|
||||
}
|
||||
|
||||
var sbalter = new StringBuilder();
|
||||
var allTable = _orm.Ado.Query<string>(CommandType.Text,
|
||||
@"SHOW TABLES");
|
||||
//如果旧表名和现表名均不存在,则直接创建表
|
||||
if (string.IsNullOrWhiteSpace(tboldname) && allTable.Any(s => s.Equals(tbname)) == false)
|
||||
{
|
||||
//创建表
|
||||
var createTableName = _commonUtils.QuoteSqlName(tbname);
|
||||
sbalter.Append("CREATE TABLE ").Append(createTableName).Append(" ( ");
|
||||
foreach (var tbcol in tb.ColumnsByPosition)
|
||||
{
|
||||
sbalter.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ")
|
||||
.Append(tbcol.Attribute.DbType);
|
||||
if (tbcol.Attribute.IsIdentity == true)
|
||||
{
|
||||
//No IsIdentity
|
||||
}
|
||||
|
||||
sbalter.Append(",");
|
||||
}
|
||||
|
||||
sbalter.Remove(sbalter.Length - 1, 1);
|
||||
sbalter.Append(") ");
|
||||
if (tb.Indexes.Any())
|
||||
{
|
||||
sbalter.Append(",\r\n");
|
||||
}
|
||||
|
||||
//创建表的索引
|
||||
foreach (var uk in tb.Indexes)
|
||||
{
|
||||
sbalter.Append($"INDEX (");
|
||||
foreach (var tbcol in uk.Columns)
|
||||
{
|
||||
if (tbcol.Column.Attribute.DbType != "SYMBOL")
|
||||
throw new Exception("索引只能是string类型且[Column(DbType = \"symbol\")]");
|
||||
sbalter.Append($"{_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)}");
|
||||
}
|
||||
|
||||
sbalter.Append($"),");
|
||||
}
|
||||
|
||||
sbalter.Remove(sbalter.Length - 1, 1);
|
||||
//是否存在分表
|
||||
foreach (var propety in obj.tableSchema.Type.GetProperties())
|
||||
{
|
||||
var timeAttr = propety.GetCustomAttribute<AutoSubtableAttribute>();
|
||||
if (timeAttr != null)
|
||||
{
|
||||
var ckey = propety.Name;
|
||||
//如果存在Column.Name
|
||||
var colNameAttr = propety.GetCustomAttribute<ColumnAttribute>();
|
||||
if (!string.IsNullOrWhiteSpace(colNameAttr?.Name))
|
||||
//则以Column中的Name为主
|
||||
ckey = colNameAttr.Name;
|
||||
var colName = tb.Columns.FirstOrDefault(it => it.Key == ckey).Value;
|
||||
sbalter.Append(
|
||||
$" TIMESTAMP({colName.Attribute.Name}) PARTITION BY {timeAttr.SubtableType};{Environment.NewLine}");
|
||||
}
|
||||
}
|
||||
}
|
||||
//如果旧表名特性存在,旧表名在数据库中存在,现表名在数据库中不存在,直接走修改表名逻辑
|
||||
else if (string.IsNullOrWhiteSpace(tboldname) == false && allTable.Any(s => s.Equals(tboldname)) &&
|
||||
allTable.Any(s => s.Equals(tbname)) == false)
|
||||
{
|
||||
//修改表名
|
||||
sbalter.Append("RENAME TABLE ")
|
||||
.Append(_commonUtils.QuoteSqlName(tboldname))
|
||||
.Append(" TO ").Append(_commonUtils.QuoteSqlName(tbname))
|
||||
.Append($";{Environment.NewLine}");
|
||||
}
|
||||
//如果旧表名特性存在,旧表名在数据库中不存在,现表名在数据库中存在,对比列
|
||||
//如果旧表名特性不存在 现表名在数据库中存在,对比列
|
||||
else if ((string.IsNullOrWhiteSpace(tboldname) == false &&
|
||||
allTable.Any(s => s.Equals(tboldname)) == false &&
|
||||
allTable.Any(s => s.Equals(tbname)) == true)
|
||||
|| (string.IsNullOrWhiteSpace(tboldname) == true &&
|
||||
allTable.Any(s => s.Equals(tbname)) == true))
|
||||
|
||||
{
|
||||
//查询列
|
||||
var questDbColumnInfo = _orm.Ado.ExecuteArray($"SHOW COLUMNS FROM '{tbname}'").Select(o => new
|
||||
{
|
||||
columnName = o[0].ToString(),
|
||||
indexed = Convert.ToBoolean(o[2])
|
||||
}).ToList();
|
||||
//对比列
|
||||
foreach (var tbcol in tb.ColumnsByPosition)
|
||||
{
|
||||
//如果旧列名存在 现列名均不存在 直接添加列
|
||||
if (questDbColumnInfo.Any(a => a.columnName.Equals(tbcol.Attribute.OldName)) == false
|
||||
&& questDbColumnInfo.Any(a => a.columnName.Equals(tbcol.Attribute.Name)) ==
|
||||
false)
|
||||
{
|
||||
sbalter.Append("ALTER TABLE ").Append(tbname)
|
||||
.Append(" ADD COLUMN ").Append(tbcol.Attribute.Name).Append(" ")
|
||||
.Append(tbcol.Attribute.DbType).Append($";{Environment.NewLine}");
|
||||
questDbColumnInfo.Add(new
|
||||
{
|
||||
columnName = tbcol.Attribute.Name,
|
||||
indexed = false
|
||||
});
|
||||
}
|
||||
//如果旧列名存在,现列名不存在,直接修改列名
|
||||
else if (questDbColumnInfo.Any(a =>
|
||||
a.columnName.ToString().Equals(tbcol.Attribute.OldName)) == true
|
||||
&& questDbColumnInfo.Any(a => a.columnName.ToString().Equals(tbcol.Attribute.Name)) ==
|
||||
false)
|
||||
{
|
||||
sbalter.Append("ALTER TABLE ").Append(tbname)
|
||||
.Append(" RENAME COLUMN ").Append(tbcol.Attribute.OldName).Append(" TO ")
|
||||
.Append(tbcol.Attribute.Name).Append($";{Environment.NewLine}");
|
||||
}
|
||||
}
|
||||
|
||||
//对比索引
|
||||
foreach (var uk in tb.Indexes)
|
||||
{
|
||||
if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false)
|
||||
continue;
|
||||
var ukname = ReplaceIndexName(uk.Name, tbname);
|
||||
//先判断表中有没此字段的索引
|
||||
var isIndex = questDbColumnInfo
|
||||
.Where(a => a.columnName.ToString().Equals(uk.Columns.First().Column.Attribute.Name))
|
||||
.FirstOrDefault()?.indexed;
|
||||
//如果此字段不是索引
|
||||
if (isIndex != null && isIndex == false)
|
||||
{
|
||||
//创建索引
|
||||
sbalter.Append($"ALTER TABLE {tbname} ALTER COLUMN ");
|
||||
foreach (var tbcol in uk.Columns)
|
||||
{
|
||||
if (tbcol.Column.Attribute.DbType != "SYMBOL")
|
||||
throw new Exception("索引只能是string类型且[Column(DbType = \"symbol\")]");
|
||||
sbalter.Append($"{tbcol.Column.Attribute.Name}");
|
||||
}
|
||||
|
||||
sbalter.Append($" ADD INDEX;{Environment.NewLine}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sb.Append(sbalter);
|
||||
}
|
||||
|
||||
return sb.Length == 0 ? null : sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
26
Providers/FreeSql.Provider.QuestDb/QuestDbContainer.cs
Normal file
26
Providers/FreeSql.Provider.QuestDb/QuestDbContainer.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace FreeSql.Provider.QuestDb
|
||||
{
|
||||
internal class QuestDbContainer
|
||||
{
|
||||
//作用于HttpClientFatory
|
||||
private static IServiceCollection Services;
|
||||
internal static IServiceProvider ServiceProvider { get; private set; }
|
||||
|
||||
internal static void Initialize(Action<IServiceCollection> service)
|
||||
{
|
||||
Services = new ServiceCollection();
|
||||
service?.Invoke(Services);
|
||||
ServiceProvider = Services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
internal static T GetService<T>()
|
||||
{
|
||||
return ServiceProvider.GetService<T>();
|
||||
}
|
||||
}
|
||||
}
|
793
Providers/FreeSql.Provider.QuestDb/QuestDbDbFirst.cs
Normal file
793
Providers/FreeSql.Provider.QuestDb/QuestDbDbFirst.cs
Normal file
@ -0,0 +1,793 @@
|
||||
using FreeSql.DatabaseModel;
|
||||
using FreeSql.Internal;
|
||||
using FreeSql.Internal.Model;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NpgsqlTypes;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace FreeSql.QuestDb
|
||||
{
|
||||
class QuestDbDbFirst : IDbFirst
|
||||
{
|
||||
IFreeSql _orm;
|
||||
protected CommonUtils _commonUtils;
|
||||
protected CommonExpression _commonExpression;
|
||||
|
||||
public QuestDbDbFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
|
||||
{
|
||||
_orm = orm;
|
||||
_commonUtils = commonUtils;
|
||||
_commonExpression = commonExpression;
|
||||
}
|
||||
|
||||
public bool IsPg10 => ServerVersion >= 10;
|
||||
|
||||
public int ServerVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_ServerVersionValue == 0 && _orm.Ado.MasterPool != null)
|
||||
using (var conn = _orm.Ado.MasterPool.Get())
|
||||
{
|
||||
try
|
||||
{
|
||||
_ServerVersionValue = ParsePgVersion(conn.Value.ServerVersion, 10, 0).Item2;
|
||||
}
|
||||
catch
|
||||
{
|
||||
_ServerVersionValue = 9;
|
||||
}
|
||||
}
|
||||
|
||||
return _ServerVersionValue;
|
||||
}
|
||||
}
|
||||
|
||||
int _ServerVersionValue = 0;
|
||||
|
||||
public int GetDbType(DbColumnInfo column) => (int)GetNpgsqlDbType(column);
|
||||
|
||||
NpgsqlDbType GetNpgsqlDbType(DbColumnInfo column)
|
||||
{
|
||||
var dbtype = column.DbTypeText;
|
||||
var isarray = dbtype?.EndsWith("[]") == true;
|
||||
if (isarray) dbtype = dbtype.Remove(dbtype.Length - 2);
|
||||
NpgsqlDbType ret = NpgsqlDbType.Unknown;
|
||||
switch (dbtype?.ToLower().TrimStart('_'))
|
||||
{
|
||||
case "short":
|
||||
ret = NpgsqlDbType.Smallint;
|
||||
break;
|
||||
case "int":
|
||||
ret = NpgsqlDbType.Integer;
|
||||
break;
|
||||
case "long":
|
||||
ret = NpgsqlDbType.Bigint;
|
||||
break;
|
||||
case "numeric":
|
||||
ret = NpgsqlDbType.Numeric;
|
||||
break;
|
||||
case "float":
|
||||
ret = NpgsqlDbType.Real;
|
||||
break;
|
||||
case "double":
|
||||
ret = NpgsqlDbType.Double;
|
||||
break;
|
||||
case "char":
|
||||
ret = NpgsqlDbType.Char;
|
||||
break;
|
||||
case "string":
|
||||
ret = NpgsqlDbType.Varchar;
|
||||
break;
|
||||
case "timestamp":
|
||||
ret = NpgsqlDbType.Timestamp;
|
||||
break;
|
||||
case "timestamptz":
|
||||
ret = NpgsqlDbType.TimestampTz;
|
||||
break;
|
||||
case "date":
|
||||
ret = NpgsqlDbType.Date;
|
||||
break;
|
||||
case "time":
|
||||
ret = NpgsqlDbType.Time;
|
||||
break;
|
||||
case "timetz":
|
||||
ret = NpgsqlDbType.TimeTz;
|
||||
break;
|
||||
case "interval":
|
||||
ret = NpgsqlDbType.Interval;
|
||||
break;
|
||||
|
||||
case "bool":
|
||||
ret = NpgsqlDbType.Boolean;
|
||||
break;
|
||||
case "bytea":
|
||||
ret = NpgsqlDbType.Bytea;
|
||||
break;
|
||||
case "bit":
|
||||
ret = NpgsqlDbType.Bit;
|
||||
break;
|
||||
case "varbit":
|
||||
ret = NpgsqlDbType.Varbit;
|
||||
break;
|
||||
|
||||
case "point":
|
||||
ret = NpgsqlDbType.Point;
|
||||
break;
|
||||
case "line":
|
||||
ret = NpgsqlDbType.Line;
|
||||
break;
|
||||
case "lseg":
|
||||
ret = NpgsqlDbType.LSeg;
|
||||
break;
|
||||
case "box":
|
||||
ret = NpgsqlDbType.Box;
|
||||
break;
|
||||
case "path":
|
||||
ret = NpgsqlDbType.Path;
|
||||
break;
|
||||
case "polygon":
|
||||
ret = NpgsqlDbType.Polygon;
|
||||
break;
|
||||
case "circle":
|
||||
ret = NpgsqlDbType.Circle;
|
||||
break;
|
||||
|
||||
case "cidr":
|
||||
ret = NpgsqlDbType.Cidr;
|
||||
break;
|
||||
case "inet":
|
||||
ret = NpgsqlDbType.Inet;
|
||||
break;
|
||||
case "macaddr":
|
||||
ret = NpgsqlDbType.MacAddr;
|
||||
break;
|
||||
|
||||
case "json":
|
||||
ret = NpgsqlDbType.Json;
|
||||
break;
|
||||
case "jsonb":
|
||||
ret = NpgsqlDbType.Jsonb;
|
||||
break;
|
||||
case "uuid":
|
||||
ret = NpgsqlDbType.Uuid;
|
||||
break;
|
||||
|
||||
case "int4range":
|
||||
ret = NpgsqlDbType.Range | NpgsqlDbType.Integer;
|
||||
break;
|
||||
case "int8range":
|
||||
ret = NpgsqlDbType.Range | NpgsqlDbType.Bigint;
|
||||
break;
|
||||
case "numrange":
|
||||
ret = NpgsqlDbType.Range | NpgsqlDbType.Numeric;
|
||||
break;
|
||||
case "tsrange":
|
||||
ret = NpgsqlDbType.Range | NpgsqlDbType.Timestamp;
|
||||
break;
|
||||
case "tstzrange":
|
||||
ret = NpgsqlDbType.Range | NpgsqlDbType.TimestampTz;
|
||||
break;
|
||||
case "daterange":
|
||||
ret = NpgsqlDbType.Range | NpgsqlDbType.Date;
|
||||
break;
|
||||
|
||||
case "hstore":
|
||||
ret = NpgsqlDbType.Hstore;
|
||||
break;
|
||||
case "geometry":
|
||||
ret = NpgsqlDbType.Geometry;
|
||||
break;
|
||||
}
|
||||
|
||||
return isarray ? (ret | NpgsqlDbType.Array) : ret;
|
||||
}
|
||||
|
||||
static readonly
|
||||
Dictionary<int, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type
|
||||
csNullableTypeInfo, string csTypeValue, string dataReaderMethod)> _dicDbToCs =
|
||||
new Dictionary<int, (string csConvert, string csParse, string csStringify, string csType, Type
|
||||
csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)>()
|
||||
{
|
||||
{
|
||||
(int)NpgsqlDbType.Smallint,
|
||||
("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?),
|
||||
"{0}.Value", "GetInt16")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Integer,
|
||||
("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value",
|
||||
"GetInt32")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Bigint,
|
||||
("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?),
|
||||
"{0}.Value", "GetInt64")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Numeric,
|
||||
("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal),
|
||||
typeof(decimal?), "{0}.Value", "GetDecimal")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Real,
|
||||
("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?),
|
||||
"{0}.Value", "GetFloat")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Double,
|
||||
("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?),
|
||||
"{0}.Value", "GetDouble")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Money,
|
||||
("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal),
|
||||
typeof(decimal?), "{0}.Value", "GetDecimal")
|
||||
},
|
||||
|
||||
{
|
||||
(int)NpgsqlDbType.Char,
|
||||
("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string",
|
||||
typeof(string), typeof(string), "{0}", "GetString")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Varchar,
|
||||
("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string",
|
||||
typeof(string), typeof(string), "{0}", "GetString")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Text,
|
||||
("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string",
|
||||
typeof(string), typeof(string), "{0}", "GetString")
|
||||
},
|
||||
|
||||
{
|
||||
(int)NpgsqlDbType.Timestamp,
|
||||
("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?",
|
||||
typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.TimestampTz,
|
||||
("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?",
|
||||
typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Date,
|
||||
("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?",
|
||||
typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Time,
|
||||
("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?",
|
||||
typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.TimeTz,
|
||||
("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?",
|
||||
typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Interval,
|
||||
("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?",
|
||||
typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue")
|
||||
},
|
||||
|
||||
{
|
||||
(int)NpgsqlDbType.Boolean,
|
||||
("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?),
|
||||
"{0}.Value", "GetBoolean")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Bytea,
|
||||
("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]",
|
||||
typeof(byte[]), typeof(byte[]), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Bit,
|
||||
("(BitArray)", "{0}.ToBitArray()", "{0}.To1010()", "BitArray", typeof(BitArray),
|
||||
typeof(BitArray), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Varbit,
|
||||
("(BitArray)", "{0}.ToBitArray()", "{0}.To1010()", "BitArray", typeof(BitArray),
|
||||
typeof(BitArray), "{0}", "GetValue")
|
||||
},
|
||||
|
||||
{
|
||||
(int)NpgsqlDbType.Point,
|
||||
("(NpgsqlPoint?)", "NpgsqlPoint.Parse({0})", "{0}.ToString()", "NpgsqlPoint",
|
||||
typeof(NpgsqlPoint), typeof(NpgsqlPoint?), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Line,
|
||||
("(NpgsqlLine?)", "NpgsqlLine.Parse({0})", "{0}.ToString()", "NpgsqlLine", typeof(NpgsqlLine),
|
||||
typeof(NpgsqlLine?), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.LSeg,
|
||||
("(NpgsqlLSeg?)", "NpgsqlLSeg.Parse({0})", "{0}.ToString()", "NpgsqlLSeg", typeof(NpgsqlLSeg),
|
||||
typeof(NpgsqlLSeg?), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Box,
|
||||
("(NpgsqlBox?)", "NpgsqlBox.Parse({0})", "{0}.ToString()", "NpgsqlBox", typeof(NpgsqlBox),
|
||||
typeof(NpgsqlBox?), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Path,
|
||||
("(NpgsqlPath?)", "NpgsqlPath.Parse({0})", "{0}.ToString()", "NpgsqlPath", typeof(NpgsqlPath),
|
||||
typeof(NpgsqlPath?), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Polygon,
|
||||
("(NpgsqlPolygon?)", "NpgsqlPolygon.Parse({0})", "{0}.ToString()", "NpgsqlPolygon",
|
||||
typeof(NpgsqlPolygon), typeof(NpgsqlPolygon?), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Circle,
|
||||
("(NpgsqlCircle?)", "NpgsqlCircle.Parse({0})", "{0}.ToString()", "NpgsqlCircle",
|
||||
typeof(NpgsqlCircle), typeof(NpgsqlCircle?), "{0}", "GetValue")
|
||||
},
|
||||
|
||||
{
|
||||
(int)NpgsqlDbType.Cidr,
|
||||
("((IPAddress, int)?)", "(IPAddress, int)({0})", "{0}.ToString()", "(IPAddress, int)",
|
||||
typeof((IPAddress, int)), typeof((IPAddress, int)?), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Inet,
|
||||
("(IPAddress)", "IPAddress.Parse({0})", "{0}.ToString()", "IPAddress", typeof(IPAddress),
|
||||
typeof(IPAddress), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.MacAddr,
|
||||
("(PhysicalAddress?)", "PhysicalAddress.Parse({0})", "{0}.ToString()", "PhysicalAddress",
|
||||
typeof(PhysicalAddress), typeof(PhysicalAddress), "{0}", "GetValue")
|
||||
},
|
||||
|
||||
{
|
||||
(int)NpgsqlDbType.Json,
|
||||
("(JToken)", "JToken.Parse({0})", "{0}.ToString()", "JToken", typeof(JToken), typeof(JToken),
|
||||
"{0}", "GetString")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Jsonb,
|
||||
("(JToken)", "JToken.Parse({0})", "{0}.ToString()", "JToken", typeof(JToken), typeof(JToken),
|
||||
"{0}", "GetString")
|
||||
},
|
||||
{
|
||||
(int)NpgsqlDbType.Uuid,
|
||||
("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid", typeof(Guid), typeof(Guid?), "{0}",
|
||||
"GetString")
|
||||
},
|
||||
|
||||
{
|
||||
(int)(NpgsqlDbType.Range | NpgsqlDbType.Integer),
|
||||
("(NpgsqlRange<int>?)", "{0}.ToNpgsqlRange<int>()", "{0}.ToString()", "NpgsqlRange<int>",
|
||||
typeof(NpgsqlRange<int>), typeof(NpgsqlRange<int>?), "{0}", "GetString")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Range | NpgsqlDbType.Bigint),
|
||||
("(NpgsqlRange<long>?)", "{0}.ToNpgsqlRange<long>()", "{0}.ToString()", "NpgsqlRange<long>",
|
||||
typeof(NpgsqlRange<long>), typeof(NpgsqlRange<long>?), "{0}", "GetString")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Range | NpgsqlDbType.Numeric),
|
||||
("(NpgsqlRange<decimal>?)", "{0}.ToNpgsqlRange<decimal>()", "{0}.ToString()",
|
||||
"NpgsqlRange<decimal>", typeof(NpgsqlRange<decimal>), typeof(NpgsqlRange<decimal>?), "{0}",
|
||||
"GetString")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Range | NpgsqlDbType.Timestamp),
|
||||
("(NpgsqlRange<DateTime>?)", "{0}.ToNpgsqlRange<DateTime>()", "{0}.ToString()",
|
||||
"NpgsqlRange<DateTime>", typeof(NpgsqlRange<DateTime>), typeof(NpgsqlRange<DateTime>?),
|
||||
"{0}", "GetString")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Range | NpgsqlDbType.TimestampTz),
|
||||
("(NpgsqlRange<DateTime>?)", "{0}.ToNpgsqlRange<DateTime>()", "{0}.ToString()",
|
||||
"NpgsqlRange<DateTime>", typeof(NpgsqlRange<DateTime>), typeof(NpgsqlRange<DateTime>?),
|
||||
"{0}", "GetString")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Range | NpgsqlDbType.Date),
|
||||
("(NpgsqlRange<DateTime>?)", "{0}.ToNpgsqlRange<DateTime>()", "{0}.ToString()",
|
||||
"NpgsqlRange<DateTime>", typeof(NpgsqlRange<DateTime>), typeof(NpgsqlRange<DateTime>?),
|
||||
"{0}", "GetString")
|
||||
},
|
||||
|
||||
{
|
||||
(int)NpgsqlDbType.Hstore,
|
||||
("(Dictionary<string, string>)",
|
||||
"JsonConvert.DeserializeObject<Dictionary<string, string>>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "Dictionary<string, string>",
|
||||
typeof(Dictionary<string, string>), typeof(Dictionary<string, string>), "{0}", "GetValue")
|
||||
},
|
||||
|
||||
/*** array ***/
|
||||
|
||||
{
|
||||
(int)(NpgsqlDbType.Smallint | NpgsqlDbType.Array),
|
||||
("(short[])", "JsonConvert.DeserializeObject<short[]>({0})", "JsonConvert.SerializeObject({0})",
|
||||
"short[]", typeof(short[]), typeof(short[]), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Integer | NpgsqlDbType.Array),
|
||||
("(int[])", "JsonConvert.DeserializeObject<int[]>({0})", "JsonConvert.SerializeObject({0})",
|
||||
"int[]", typeof(int[]), typeof(int[]), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Bigint | NpgsqlDbType.Array),
|
||||
("(long[])", "JsonConvert.DeserializeObject<long[]>({0})", "JsonConvert.SerializeObject({0})",
|
||||
"long[]", typeof(long[]), typeof(long[]), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Numeric | NpgsqlDbType.Array),
|
||||
("(decimal[])", "JsonConvert.DeserializeObject<decimal[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "decimal[]", typeof(decimal[]), typeof(decimal[]),
|
||||
"{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Real | NpgsqlDbType.Array),
|
||||
("(float[])", "JsonConvert.DeserializeObject<float[]>({0})", "JsonConvert.SerializeObject({0})",
|
||||
"float[]", typeof(float[]), typeof(float[]), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Double | NpgsqlDbType.Array),
|
||||
("(double[])", "JsonConvert.DeserializeObject<double[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "double[]", typeof(double[]), typeof(double[]), "{0}",
|
||||
"GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Money | NpgsqlDbType.Array),
|
||||
("(decimal[])", "JsonConvert.DeserializeObject<decimal[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "decimal[]", typeof(decimal[]), typeof(decimal[]),
|
||||
"{0}", "GetValue")
|
||||
},
|
||||
|
||||
{
|
||||
(int)(NpgsqlDbType.Char | NpgsqlDbType.Array),
|
||||
("(string[])", "JsonConvert.DeserializeObject<string[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "string[]", typeof(string[]), typeof(string[]), "{0}",
|
||||
"GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Varchar | NpgsqlDbType.Array),
|
||||
("(string[])", "JsonConvert.DeserializeObject<string[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "string[]", typeof(string[]), typeof(string[]), "{0}",
|
||||
"GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Text | NpgsqlDbType.Array),
|
||||
("(string[])", "JsonConvert.DeserializeObject<string[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "string[]", typeof(string[]), typeof(string[]), "{0}",
|
||||
"GetValue")
|
||||
},
|
||||
|
||||
{
|
||||
(int)(NpgsqlDbType.Timestamp | NpgsqlDbType.Array),
|
||||
("(DateTime[])", "JsonConvert.DeserializeObject<DateTime[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "DateTime[]", typeof(DateTime[]), typeof(DateTime[]),
|
||||
"{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.TimestampTz | NpgsqlDbType.Array),
|
||||
("(DateTime[])", "JsonConvert.DeserializeObject<DateTime[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "DateTime[]", typeof(DateTime[]), typeof(DateTime[]),
|
||||
"{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Date | NpgsqlDbType.Array),
|
||||
("(DateTime[])", "JsonConvert.DeserializeObject<DateTime[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "DateTime[]", typeof(DateTime[]), typeof(DateTime[]),
|
||||
"{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Time | NpgsqlDbType.Array),
|
||||
("(TimeSpan[])", "JsonConvert.DeserializeObject<TimeSpan[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "TimeSpan[]", typeof(TimeSpan[]), typeof(TimeSpan[]),
|
||||
"{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.TimeTz | NpgsqlDbType.Array),
|
||||
("(TimeSpan[])", "JsonConvert.DeserializeObject<TimeSpan[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "TimeSpan[]", typeof(TimeSpan[]), typeof(TimeSpan[]),
|
||||
"{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Interval | NpgsqlDbType.Array),
|
||||
("(TimeSpan[])", "JsonConvert.DeserializeObject<TimeSpan[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "TimeSpan[]", typeof(TimeSpan[]), typeof(TimeSpan[]),
|
||||
"{0}", "GetValue")
|
||||
},
|
||||
|
||||
{
|
||||
(int)(NpgsqlDbType.Boolean | NpgsqlDbType.Array),
|
||||
("(bool[])", "JsonConvert.DeserializeObject<bool[]>({0})", "JsonConvert.SerializeObject({0})",
|
||||
"bool[]", typeof(bool[]), typeof(bool[]), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Bytea | NpgsqlDbType.Array),
|
||||
("(byte[][])", "JsonConvert.DeserializeObject<byte[][]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "byte[][]", typeof(byte[][]), typeof(byte[][]), "{0}",
|
||||
"GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Bit | NpgsqlDbType.Array),
|
||||
("(BitArray[])", "JsonConvert.DeserializeObject<BitArray[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "BitArray[]", typeof(BitArray[]), typeof(BitArray[]),
|
||||
"{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Varbit | NpgsqlDbType.Array),
|
||||
("(BitArray[])", "JsonConvert.DeserializeObject<BitArray[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "BitArray[]", typeof(BitArray[]), typeof(BitArray[]),
|
||||
"{0}", "GetValue")
|
||||
},
|
||||
|
||||
{
|
||||
(int)(NpgsqlDbType.Point | NpgsqlDbType.Array),
|
||||
("(NpgsqlPoint[])", "JsonConvert.DeserializeObject<NpgsqlPoint[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "NpgsqlPoint[]", typeof(NpgsqlPoint[]),
|
||||
typeof(NpgsqlPoint[]), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Line | NpgsqlDbType.Array),
|
||||
("(NpgsqlLine[])", "JsonConvert.DeserializeObject<BNpgsqlLineitArray[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "NpgsqlLine[]", typeof(NpgsqlLine[]),
|
||||
typeof(NpgsqlLine[]), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.LSeg | NpgsqlDbType.Array),
|
||||
("(NpgsqlLSeg[])", "JsonConvert.DeserializeObject<NpgsqlLSeg[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "NpgsqlLSeg[]", typeof(NpgsqlLSeg[]),
|
||||
typeof(NpgsqlLSeg[]), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Box | NpgsqlDbType.Array),
|
||||
("(NpgsqlBox[])", "JsonConvert.DeserializeObject<NpgsqlBox[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "NpgsqlBox[]", typeof(NpgsqlBox[]), typeof(NpgsqlBox[]),
|
||||
"{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Path | NpgsqlDbType.Array),
|
||||
("(NpgsqlPath[])", "JsonConvert.DeserializeObject<NpgsqlPath[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "NpgsqlPath[]", typeof(NpgsqlPath[]),
|
||||
typeof(NpgsqlPath[]), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Polygon | NpgsqlDbType.Array),
|
||||
("(NpgsqlPolygon[])", "JsonConvert.DeserializeObject<NpgsqlPolygon[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "NpgsqlPolygon[]", typeof(NpgsqlPolygon[]),
|
||||
typeof(NpgsqlPolygon[]), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Circle | NpgsqlDbType.Array),
|
||||
("(NpgsqlCircle[])", "JsonConvert.DeserializeObject<NpgsqlCircle[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "NpgsqlCircle[]", typeof(NpgsqlCircle[]),
|
||||
typeof(NpgsqlCircle[]), "{0}", "GetValue")
|
||||
},
|
||||
|
||||
{
|
||||
(int)(NpgsqlDbType.Cidr | NpgsqlDbType.Array),
|
||||
("((IPAddress, int)[])", "JsonConvert.DeserializeObject<(IPAddress, int)[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "(IPAddress, int)[]", typeof((IPAddress, int)[]),
|
||||
typeof((IPAddress, int)[]), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Inet | NpgsqlDbType.Array),
|
||||
("(IPAddress[])", "JsonConvert.DeserializeObject<IPAddress[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "IPAddress[]", typeof(IPAddress[]), typeof(IPAddress[]),
|
||||
"{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.MacAddr | NpgsqlDbType.Array),
|
||||
("(PhysicalAddress[])", "JsonConvert.DeserializeObject<PhysicalAddress[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "PhysicalAddress[]", typeof(PhysicalAddress[]),
|
||||
typeof(PhysicalAddress[]), "{0}", "GetValue")
|
||||
},
|
||||
|
||||
{
|
||||
(int)(NpgsqlDbType.Json | NpgsqlDbType.Array),
|
||||
("(JToken[])", "JsonConvert.DeserializeObject<JToken[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "JToken[]", typeof(JToken[]), typeof(JToken[]), "{0}",
|
||||
"GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Jsonb | NpgsqlDbType.Array),
|
||||
("(JToken[])", "JsonConvert.DeserializeObject<JToken[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "JToken[]", typeof(JToken[]), typeof(JToken[]), "{0}",
|
||||
"GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Uuid | NpgsqlDbType.Array),
|
||||
("(Guid[])", "JsonConvert.DeserializeObject<Guid[]>({0})", "JsonConvert.SerializeObject({0})",
|
||||
"Guid[]", typeof(Guid[]), typeof(Guid[]), "{0}", "GetValue")
|
||||
},
|
||||
|
||||
{
|
||||
(int)(NpgsqlDbType.Range | NpgsqlDbType.Integer | NpgsqlDbType.Array),
|
||||
("(NpgsqlRange<int>[])", "JsonConvert.DeserializeObject<NpgsqlRange<int>[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "NpgsqlRange<int>[]", typeof(NpgsqlRange<int>[]),
|
||||
typeof(NpgsqlRange<int>[]), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Range | NpgsqlDbType.Bigint | NpgsqlDbType.Array),
|
||||
("(NpgsqlRange<long>[])", "JsonConvert.DeserializeObject<NpgsqlRange<long>[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "NpgsqlRange<long>[]", typeof(NpgsqlRange<long>[]),
|
||||
typeof(NpgsqlRange<long>[]), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Range | NpgsqlDbType.Numeric | NpgsqlDbType.Array),
|
||||
("(NpgsqlRange<decimal>[])", "JsonConvert.DeserializeObject<NpgsqlRange<decimal>[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "NpgsqlRange<decimal>[]",
|
||||
typeof(NpgsqlRange<decimal>[]), typeof(NpgsqlRange<decimal>[]), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Range | NpgsqlDbType.Timestamp | NpgsqlDbType.Array),
|
||||
("(NpgsqlRange<DateTime>[])", "JsonConvert.DeserializeObject<NpgsqlRange<DateTime>[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "NpgsqlRange<DateTime>[]",
|
||||
typeof(NpgsqlRange<DateTime>[]), typeof(NpgsqlRange<DateTime>[]), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Range | NpgsqlDbType.TimestampTz | NpgsqlDbType.Array),
|
||||
("(NpgsqlRange<DateTime>[])", "JsonConvert.DeserializeObject<NpgsqlRange<DateTime>[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "NpgsqlRange<DateTime>[]",
|
||||
typeof(NpgsqlRange<DateTime>[]), typeof(NpgsqlRange<DateTime>[]), "{0}", "GetValue")
|
||||
},
|
||||
{
|
||||
(int)(NpgsqlDbType.Range | NpgsqlDbType.Date | NpgsqlDbType.Array),
|
||||
("(NpgsqlRange<DateTime>[])", "JsonConvert.DeserializeObject<NpgsqlRange<DateTime>[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "NpgsqlRange<DateTime>[]",
|
||||
typeof(NpgsqlRange<DateTime>[]), typeof(NpgsqlRange<DateTime>[]), "{0}", "GetValue")
|
||||
},
|
||||
|
||||
{
|
||||
(int)(NpgsqlDbType.Hstore | NpgsqlDbType.Array),
|
||||
("(Dictionary<string, string>[])",
|
||||
"JsonConvert.DeserializeObject<Dictionary<string, string>[]>({0})",
|
||||
"JsonConvert.SerializeObject({0})", "Dictionary<string, string>[]",
|
||||
typeof(Dictionary<string, string>[]), typeof(Dictionary<string, string>[]), "{0}",
|
||||
"GetValue")
|
||||
},
|
||||
};
|
||||
|
||||
public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc)
|
||||
? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", ""))
|
||||
: null;
|
||||
|
||||
public string GetCsParse(DbColumnInfo column) =>
|
||||
_dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csParse : null;
|
||||
|
||||
public string GetCsStringify(DbColumnInfo column) =>
|
||||
_dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csStringify : null;
|
||||
|
||||
public string GetCsType(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc)
|
||||
? (column.IsNullable ? trydc.csType : trydc.csType.Replace("?", ""))
|
||||
: null;
|
||||
|
||||
public Type GetCsTypeInfo(DbColumnInfo column) =>
|
||||
_dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeInfo : null;
|
||||
|
||||
public string GetCsTypeValue(DbColumnInfo column) =>
|
||||
_dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeValue : null;
|
||||
|
||||
public string GetDataReaderMethod(DbColumnInfo column) =>
|
||||
_dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.dataReaderMethod : null;
|
||||
|
||||
public List<string> GetDatabases()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool ExistsTable(string name, bool ignoreCase)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name)) return false;
|
||||
var tbnameArray = _commonUtils.SplitTableName(name);
|
||||
var tbname = string.Empty;
|
||||
if (tbnameArray?.Length == 1)
|
||||
tbname = tbnameArray.FirstOrDefault();
|
||||
var resList = _orm.Ado.Query<string>(CommandType.Text, @"SHOW TABLES");
|
||||
var res = false;
|
||||
if (ignoreCase)
|
||||
res = resList.Any(s => s.ToLower().Equals(tbname.ToLower()));
|
||||
else
|
||||
res = resList.Any(s => s.Equals(tbname));
|
||||
return res;
|
||||
}
|
||||
|
||||
public DbTableInfo GetTableByName(string name, bool ignoreCase = true)
|
||||
{
|
||||
var tableColumns = _orm.Ado.ExecuteDataTable($"SHOW COLUMNS FROM '{name}'");
|
||||
List<DbColumnInfo> dbColumnInfos = new List<DbColumnInfo>();
|
||||
var dbTableInfo = new DbTableInfo()
|
||||
{
|
||||
Name = name,
|
||||
Columns = new List<DbColumnInfo>()
|
||||
};
|
||||
foreach (DataRow tableColumnsRow in tableColumns.Rows)
|
||||
{
|
||||
dbColumnInfos.Add(new DbColumnInfo()
|
||||
{
|
||||
Name = tableColumnsRow["column"].ToString(),
|
||||
DbTypeText = tableColumnsRow["type"].ToString(),
|
||||
Table = dbTableInfo,
|
||||
});
|
||||
}
|
||||
|
||||
dbTableInfo.Columns = dbColumnInfos;
|
||||
return dbTableInfo;
|
||||
}
|
||||
|
||||
public List<DbTableInfo> GetTablesByDatabase(params string[] database)
|
||||
{
|
||||
return GetTables(database, null, false);
|
||||
}
|
||||
|
||||
public List<DbTableInfo> GetTables(string[] database, string tablename, bool ignoreCase)
|
||||
{
|
||||
var resList = _orm.Ado.Query<string>(CommandType.Text, @"SHOW TABLES");
|
||||
|
||||
var tables = new List<DbTableInfo>();
|
||||
|
||||
resList.ForEach(s =>
|
||||
{
|
||||
var tableColumns = _orm.Ado.ExecuteDataTable($"SHOW COLUMNS FROM '{s}'");
|
||||
List<DbColumnInfo> dbColumnInfos = new List<DbColumnInfo>();
|
||||
var dbTableInfo = new DbTableInfo()
|
||||
{
|
||||
Name = s,
|
||||
Columns = new List<DbColumnInfo>()
|
||||
};
|
||||
foreach (DataRow tableColumnsRow in tableColumns.Rows)
|
||||
{
|
||||
dbColumnInfos.Add(new DbColumnInfo()
|
||||
{
|
||||
Name = tableColumnsRow["column"].ToString(),
|
||||
DbTypeText = tableColumnsRow["type"].ToString(),
|
||||
Table = dbTableInfo,
|
||||
});
|
||||
}
|
||||
|
||||
dbTableInfo.Columns = dbColumnInfos;
|
||||
tables.Add(dbTableInfo);
|
||||
});
|
||||
return tables;
|
||||
}
|
||||
|
||||
public List<DbEnumInfo> GetEnumsByDatabase(params string[] database)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static NativeTuple<bool, int, int> ParsePgVersion(string versionString, int v1, int v2)
|
||||
{
|
||||
int[] version = new int[] { 0, 0 };
|
||||
var vmatch = Regex.Match(versionString, @"(\d+)\.(\d+)");
|
||||
if (vmatch.Success)
|
||||
{
|
||||
version[0] = int.Parse(vmatch.Groups[1].Value);
|
||||
version[1] = int.Parse(vmatch.Groups[2].Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
vmatch = Regex.Match(versionString, @"(\d+)");
|
||||
version[0] = int.Parse(vmatch.Groups[1].Value);
|
||||
}
|
||||
|
||||
if (version[0] > v1)
|
||||
return NativeTuple.Create(true, version[0], version[1]);
|
||||
if (version[0] == v1 && version[1] >= v2)
|
||||
return NativeTuple.Create(true, version[0], version[1]);
|
||||
return NativeTuple.Create(false, version[0], version[1]);
|
||||
}
|
||||
}
|
||||
}
|
634
Providers/FreeSql.Provider.QuestDb/QuestDbExpression.cs
Normal file
634
Providers/FreeSql.Provider.QuestDb/QuestDbExpression.cs
Normal file
@ -0,0 +1,634 @@
|
||||
using FreeSql.Internal;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace FreeSql.QuestDb
|
||||
{
|
||||
class QuestDbExpression : CommonExpression
|
||||
{
|
||||
public QuestDbExpression(CommonUtils common) : base(common)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc)
|
||||
{
|
||||
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
|
||||
switch (exp.NodeType)
|
||||
{
|
||||
case ExpressionType.ArrayLength:
|
||||
var arrOper = (exp as UnaryExpression)?.Operand;
|
||||
if (arrOper.Type == typeof(byte[])) return $"length({getExp(arrOper)})";
|
||||
break;
|
||||
case ExpressionType.Convert:
|
||||
var operandExp = (exp as UnaryExpression)?.Operand;
|
||||
var gentype = exp.Type.NullableTypeOrThis();
|
||||
if (gentype != operandExp.Type.NullableTypeOrThis())
|
||||
{
|
||||
switch (exp.Type.NullableTypeOrThis().ToString())
|
||||
{
|
||||
case "System.Boolean":
|
||||
return $"(cast({getExp(operandExp)} as string) not in ('0','false','f','no'))";
|
||||
case "System.Byte": return $"cast({getExp(operandExp)} byte)";
|
||||
case "System.Char": return $"left(cast({getExp(operandExp)} as string), 1)";
|
||||
case "System.DateTime":
|
||||
return ExpressionConstDateTime(operandExp) ?? $"cast({getExp(operandExp)} as timestamp)";
|
||||
case "System.Decimal": return $"cast({getExp(operandExp)} as double)";
|
||||
case "System.Double": return $"cast({getExp(operandExp)} as double)";
|
||||
case "System.Int16": return $"cast({getExp(operandExp)} as short)";
|
||||
case "System.Int32": return $"cast({getExp(operandExp)} as int)";
|
||||
case "System.Int64": return $"cast({getExp(operandExp)} as long)";
|
||||
case "System.SByte": return $"cast({getExp(operandExp)} as byte)";
|
||||
case "System.Single": return $"cast({getExp(operandExp)} as float)";
|
||||
case "System.String": return $"cast({getExp(operandExp)} as string)";
|
||||
case "System.UInt16": return $"cast({getExp(operandExp)} as short)";
|
||||
case "System.UInt32": return $"cast({getExp(operandExp)} as int)";
|
||||
case "System.UInt64": return $"cast({getExp(operandExp)} long)";
|
||||
case "System.Guid": return $"cast({getExp(operandExp)} symbol)";
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case ExpressionType.Call:
|
||||
var callExp = exp as MethodCallExpression;
|
||||
|
||||
switch (callExp.Method.Name)
|
||||
{
|
||||
case "Parse":
|
||||
case "TryParse":
|
||||
switch (callExp.Method.DeclaringType.NullableTypeOrThis().ToString())
|
||||
{
|
||||
case "System.Boolean":
|
||||
return $"(cast({getExp(callExp.Arguments[0])} as string) not in ('0','false','f','no'))";
|
||||
case "System.Byte": return $"cast({getExp(callExp.Arguments[0])} byte)";
|
||||
case "System.Char": return $"left(cast({getExp(callExp.Arguments[0])} as string), 1)";
|
||||
case "System.DateTime":
|
||||
return ExpressionConstDateTime(callExp.Arguments[0]) ?? $"cast({getExp(callExp.Arguments[0])} as timestamp)";
|
||||
case "System.Decimal": return $"cast({getExp(callExp.Arguments[0])} as double)";
|
||||
case "System.Double": return $"cast({getExp(callExp.Arguments[0])} as double)";
|
||||
case "System.Int16": return $"cast({getExp(callExp.Arguments[0])} as short)";
|
||||
case "System.Int32": return $"cast({getExp(callExp.Arguments[0])} as int)";
|
||||
case "System.Int64": return $"cast({getExp(callExp.Arguments[0])} as long)";
|
||||
case "System.SByte": return $"cast({getExp(callExp.Arguments[0])} as byte)";
|
||||
case "System.Single": return $"cast({getExp(callExp.Arguments[0])} as float)";
|
||||
case "System.String": return $"cast({getExp(callExp.Arguments[0])} as string)";
|
||||
case "System.UInt16": return $"cast({getExp(callExp.Arguments[0])} as short)";
|
||||
case "System.UInt32": return $"cast({getExp(callExp.Arguments[0])} as int)";
|
||||
case "System.UInt64": return $"cast({getExp(callExp.Arguments[0])} long)";
|
||||
case "System.Guid": return $"cast({getExp(callExp.Arguments[0])} symbol)";
|
||||
}
|
||||
break;
|
||||
case "NewGuid":
|
||||
return null;
|
||||
case "Next":
|
||||
if (callExp.Object?.Type == typeof(Random)) return "rnd_int()";
|
||||
return null;
|
||||
case "NextDouble":
|
||||
if (callExp.Object?.Type == typeof(Random)) return "rnd_double()";
|
||||
return null;
|
||||
case "Random":
|
||||
if (callExp.Method.DeclaringType.IsNumberType()) return "rnd_int()";
|
||||
return null;
|
||||
case "ToString":
|
||||
if (callExp.Object != null)
|
||||
{
|
||||
if (callExp.Object.Type.NullableTypeOrThis().IsEnum)
|
||||
{
|
||||
tsc.SetMapColumnTmp(null);
|
||||
var oldMapType = tsc.SetMapTypeReturnOld(typeof(string));
|
||||
var enumStr = ExpressionLambdaToSql(callExp.Object, tsc);
|
||||
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
|
||||
return enumStr;
|
||||
}
|
||||
var value = ExpressionGetValue(callExp.Object, out var success);
|
||||
if (success) return formatSql(value, typeof(string), null, null);
|
||||
return callExp.Arguments.Count == 0 ? $"cast({getExp(callExp.Object)} as string)" : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
var objExp = callExp.Object;
|
||||
var objType = objExp?.Type;
|
||||
if (objType?.FullName == "System.Byte[]") return null;
|
||||
|
||||
var argIndex = 0;
|
||||
if (objType == null && callExp.Method.DeclaringType == typeof(Enumerable))
|
||||
{
|
||||
objExp = callExp.Arguments.FirstOrDefault();
|
||||
objType = objExp?.Type;
|
||||
argIndex++;
|
||||
|
||||
if (objType == typeof(string))
|
||||
{
|
||||
switch (callExp.Method.Name)
|
||||
{
|
||||
case "First":
|
||||
case "FirstOrDefault":
|
||||
return $"left({getExp(callExp.Arguments[0])}, 1)";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (objType == null) objType = callExp.Method.DeclaringType;
|
||||
if (objType != null || objType.IsArrayOrList())
|
||||
{
|
||||
if (argIndex >= callExp.Arguments.Count) break;
|
||||
tsc.SetMapColumnTmp(null);
|
||||
var args1 = getExp(callExp.Arguments[argIndex]);
|
||||
var oldMapType = tsc.SetMapTypeReturnOld(tsc.mapTypeTmp);
|
||||
var oldDbParams = objExp?.NodeType == ExpressionType.MemberAccess ? tsc.SetDbParamsReturnOld(null) : null; //#900 UseGenerateCommandParameterWithLambda(true) 子查询 bug、以及 #1173 参数化 bug
|
||||
tsc.isNotSetMapColumnTmp = true;
|
||||
var left = objExp == null ? null : getExp(objExp);
|
||||
tsc.isNotSetMapColumnTmp = false;
|
||||
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
|
||||
if (oldDbParams != null) tsc.SetDbParamsReturnOld(oldDbParams);
|
||||
switch (callExp.Method.Name)
|
||||
{
|
||||
case "Contains":
|
||||
//判断 in //在各大 Provider AdoProvider 中已约定,500元素分割, 3空格\r\n4空格
|
||||
return $"(({args1}) in {left.Replace(", \r\n \r\n", $") \r\n OR ({args1}) in (")})";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ExpressionType.NewArrayInit:
|
||||
var arrExp = exp as NewArrayExpression;
|
||||
var arrSb = new StringBuilder();
|
||||
arrSb.Append("(");
|
||||
for (var a = 0; a < arrExp.Expressions.Count; a++)
|
||||
{
|
||||
if (a > 0) arrSb.Append(",");
|
||||
if (a % 500 == 499) arrSb.Append(" \r\n \r\n"); //500元素分割, 3空格\r\n4空格
|
||||
arrSb.Append(getExp(arrExp.Expressions[a]));
|
||||
}
|
||||
if (arrSb.Length == 1) arrSb.Append("NULL");
|
||||
return arrSb.Append(")").ToString();
|
||||
case ExpressionType.ListInit:
|
||||
var listExp = exp as ListInitExpression;
|
||||
var listSb = new StringBuilder();
|
||||
listSb.Append("(");
|
||||
for (var a = 0; a < listExp.Initializers.Count; a++)
|
||||
{
|
||||
if (listExp.Initializers[a].Arguments.Any() == false) continue;
|
||||
if (a > 0) listSb.Append(",");
|
||||
listSb.Append(getExp(listExp.Initializers[a].Arguments.FirstOrDefault()));
|
||||
}
|
||||
if (listSb.Length == 1) listSb.Append("NULL");
|
||||
return listSb.Append(")").ToString();
|
||||
case ExpressionType.New:
|
||||
var newExp = exp as NewExpression;
|
||||
if (typeof(IList).IsAssignableFrom(newExp.Type))
|
||||
{
|
||||
if (newExp.Arguments.Count == 0) return "(NULL)";
|
||||
if (typeof(IEnumerable).IsAssignableFrom(newExp.Arguments[0].Type) == false) return "(NULL)";
|
||||
return getExp(newExp.Arguments[0]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, ExpTSC tsc)
|
||||
{
|
||||
if (exp.Expression == null)
|
||||
{
|
||||
switch (exp.Member.Name)
|
||||
{
|
||||
case "Empty": return "''";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var left = ExpressionLambdaToSql(exp.Expression, tsc);
|
||||
switch (exp.Member.Name)
|
||||
{
|
||||
case "Length": return $"length({left})";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, ExpTSC tsc)
|
||||
{
|
||||
if (exp.Expression == null)
|
||||
{
|
||||
switch (exp.Member.Name)
|
||||
{
|
||||
case "Now": return _common.Now;
|
||||
case "UtcNow": return _common.NowUtc;
|
||||
case "Today": return $"date_trunc('day',{_common.Now})";
|
||||
case "MinValue": return "to_timestamp('0001-01-01', 'yyyy-MM-dd')";
|
||||
case "MaxValue": return "to_timestamp('9999-12-31 23:59:59.999999', 'yyyy-MM-dd HH:mm:ss.SSSUUU')";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
var left = ExpressionLambdaToSql(exp.Expression, tsc);
|
||||
switch (exp.Member.Name)
|
||||
{
|
||||
case "Date": return $"date_trunc('day',{left})";
|
||||
case "TimeOfDay": return $"(hour({left})*3600+minute({left})*60+second({left})";
|
||||
case "DayOfWeek": return $"(day_of_week_sunday_first({left})-1)";
|
||||
case "Day": return $"day({left})";
|
||||
case "DayOfYear": return $"datediff('d',date_trunc('year',{left}),{left})";
|
||||
case "Month": return $"month({left})";
|
||||
case "Year": return $"year({left})";
|
||||
case "Hour": return $"hour({left})";
|
||||
case "Minute": return $"minute({left})";
|
||||
case "Second": return $"second({left})";
|
||||
case "Millisecond":return $"millis({left})";
|
||||
case "Ticks": return $"(extract(epoch from {left})*10000000+millis({left})*10000+micros({left})*10+621355968000000000)";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, ExpTSC tsc)
|
||||
{
|
||||
if (exp.Expression == null)
|
||||
{
|
||||
switch (exp.Member.Name)
|
||||
{
|
||||
case "Zero": return "0";
|
||||
case "MinValue": return "-922337203685477580"; //微秒 Ticks / 10
|
||||
case "MaxValue": return "922337203685477580";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var left = ExpressionLambdaToSql(exp.Expression, tsc);
|
||||
switch (exp.Member.Name)
|
||||
{
|
||||
case "Days": return $"floor(({left})/{60 * 60 * 24})";
|
||||
case "Hours": return $"floor(({left})/{60 * 60}%24)";
|
||||
case "Milliseconds": return $"0";
|
||||
case "Minutes": return $"(floor(({left})/60)%60)";
|
||||
case "Seconds": return $"(({left})%60)";
|
||||
case "Ticks": return $"(({left})*{(long)1000000 * 10})";
|
||||
case "TotalDays": return $"(({left})/{60 * 60 * 24})";
|
||||
case "TotalHours": return $"(({left})/{60 * 60})";
|
||||
case "TotalMilliseconds": return $"(({left})*1000)";
|
||||
case "TotalMinutes": return $"(({left})/60)";
|
||||
case "TotalSeconds": return $"({left})";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, ExpTSC tsc)
|
||||
{
|
||||
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
|
||||
if (exp.Object == null)
|
||||
{
|
||||
switch (exp.Method.Name)
|
||||
{
|
||||
case "IsNullOrEmpty":
|
||||
var arg1 = getExp(exp.Arguments[0]);
|
||||
return $"({arg1} is null or {arg1} = '')";
|
||||
case "IsNullOrWhiteSpace":
|
||||
var arg2 = getExp(exp.Arguments[0]);
|
||||
return $"({arg2} is null or {arg2} = '' or trim({arg2}) = '')";
|
||||
case "Concat":
|
||||
if (exp.Arguments.Count == 1 && exp.Arguments[0].NodeType == ExpressionType.NewArrayInit && exp.Arguments[0] is NewArrayExpression concatNewArrExp)
|
||||
return _common.StringConcat(concatNewArrExp.Expressions.Select(a => getExp(a)).ToArray(), null);
|
||||
return _common.StringConcat(exp.Arguments.Select(a => getExp(a)).ToArray(), null);
|
||||
case "Format":
|
||||
if (exp.Arguments[0].NodeType != ExpressionType.Constant)
|
||||
throw new Exception(
|
||||
CoreStrings.Not_Implemented_Expression_ParameterUseConstant(exp, exp.Arguments[0]));
|
||||
var expArgsHack =
|
||||
exp.Arguments.Count == 2 && exp.Arguments[1].NodeType == ExpressionType.NewArrayInit
|
||||
? (exp.Arguments[1] as NewArrayExpression).Expressions
|
||||
: exp.Arguments.Where((a, z) => z > 0);
|
||||
//3个 {} 时,Arguments 解析出来是分开的
|
||||
//4个 {} 时,Arguments[1] 只能解析这个出来,然后里面是 NewArray []
|
||||
var expArgs = expArgsHack.Select(a =>
|
||||
{
|
||||
var atype = (a as UnaryExpression)?.Operand.Type.NullableTypeOrThis() ??
|
||||
a.Type.NullableTypeOrThis();
|
||||
if (atype == typeof(string))
|
||||
return $"'||{_common.IsNull(ExpressionLambdaToSql(a, tsc), "''")}||'";
|
||||
return $"'||{_common.IsNull($"cast({ExpressionLambdaToSql(a, tsc)} as string)", "''")}||'";
|
||||
}).ToArray();
|
||||
return string.Format(ExpressionLambdaToSql(exp.Arguments[0], tsc), expArgs);
|
||||
case "Join":
|
||||
if (exp.IsStringJoin(out var tolistObjectExp, out var toListMethod, out var toListArgs1))
|
||||
{
|
||||
var newToListArgs0 = Expression.Call(tolistObjectExp, toListMethod,
|
||||
Expression.Lambda(
|
||||
Expression.Call(
|
||||
typeof(SqlExtExtensions).GetMethod("StringJoinPgsqlGroupConcat"),
|
||||
Expression.Convert(toListArgs1.Body, typeof(object)),
|
||||
Expression.Convert(exp.Arguments[0], typeof(object))),
|
||||
toListArgs1.Parameters));
|
||||
var newToListSql = getExp(newToListArgs0);
|
||||
return newToListSql;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var left = getExp(exp.Object);
|
||||
switch (exp.Method.Name)
|
||||
{
|
||||
case "StartsWith":
|
||||
case "EndsWith":
|
||||
case "Contains":
|
||||
var args0Value = getExp(exp.Arguments[0]);
|
||||
if (args0Value == "NULL") return $"({left}) IS NULL";
|
||||
if (args0Value.Contains("%"))
|
||||
{
|
||||
if (exp.Method.Name == "StartsWith") return $"strpos({left}, {args0Value}) = 1";
|
||||
if (exp.Method.Name == "EndsWith") return $"strpos({left}, {args0Value}) = length({left})-length({args0Value})+1";
|
||||
return $"strpos({left}, {args0Value}) > 0";
|
||||
}
|
||||
|
||||
var likeOpt = "LIKE";
|
||||
if (exp.Arguments.Count > 1)
|
||||
{
|
||||
if (exp.Arguments[1].Type == typeof(bool) || exp.Arguments[1].Type == typeof(StringComparison)) likeOpt = "ILIKE";
|
||||
}
|
||||
|
||||
if (exp.Method.Name == "StartsWith")
|
||||
return $"({left}) {likeOpt} {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(cast({args0Value} as string) || '%')")}";
|
||||
if (exp.Method.Name == "EndsWith")
|
||||
return $"({left}) {likeOpt} {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' || cast({args0Value} as string))")}";
|
||||
if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) {likeOpt} {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
|
||||
return $"({left}) {likeOpt} ('%' || cast({args0Value} as string) || '%')";
|
||||
case "ToLower": return $"lower({left})";
|
||||
case "ToUpper": return $"upper({left})";
|
||||
case "Substring":
|
||||
var substrArgs1 = getExp(exp.Arguments[0]);
|
||||
if (long.TryParse(substrArgs1, out var testtrylng1)) substrArgs1 = (testtrylng1 + 1).ToString();
|
||||
else substrArgs1 += "+1";
|
||||
if (exp.Arguments.Count == 1) return $"substring({left}, {substrArgs1})";
|
||||
return $"substring({left}, {substrArgs1}, {getExp(exp.Arguments[1])})";
|
||||
case "IndexOf": return $"(strpos({left}, {getExp(exp.Arguments[0])})-1)";
|
||||
case "PadLeft":
|
||||
if (exp.Arguments.Count == 1) return $"lpad({left}, {getExp(exp.Arguments[0])})";
|
||||
return $"lpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
|
||||
case "PadRight":
|
||||
if (exp.Arguments.Count == 1) return $"rpad({left}, {getExp(exp.Arguments[0])})";
|
||||
return $"rpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
|
||||
case "Trim":
|
||||
case "TrimStart":
|
||||
case "TrimEnd":
|
||||
if (exp.Arguments.Count == 0)
|
||||
{
|
||||
if (exp.Method.Name == "Trim") return $"trim({left})";
|
||||
if (exp.Method.Name == "TrimStart") return $"ltrim({left})";
|
||||
if (exp.Method.Name == "TrimEnd") return $"rtrim({left})";
|
||||
}
|
||||
|
||||
var trimArg1 = "";
|
||||
var trimArg2 = "";
|
||||
foreach (var argsTrim02 in exp.Arguments)
|
||||
{
|
||||
var argsTrim01s = new[] { argsTrim02 };
|
||||
if (argsTrim02.NodeType == ExpressionType.NewArrayInit)
|
||||
{
|
||||
var arritem = argsTrim02 as NewArrayExpression;
|
||||
argsTrim01s = arritem.Expressions.ToArray();
|
||||
}
|
||||
|
||||
foreach (var argsTrim01 in argsTrim01s)
|
||||
{
|
||||
var trimChr = getExp(argsTrim01).Trim('\'');
|
||||
if (trimChr.Length == 1) trimArg1 += trimChr;
|
||||
else trimArg2 += $" || ({trimChr})";
|
||||
}
|
||||
}
|
||||
|
||||
if (exp.Method.Name == "Trim")
|
||||
left = $"trim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})";
|
||||
if (exp.Method.Name == "TrimStart")
|
||||
left = $"ltrim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})";
|
||||
if (exp.Method.Name == "TrimEnd")
|
||||
left = $"rtrim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})";
|
||||
return left;
|
||||
case "Replace": return $"replace({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
|
||||
case "CompareTo": return $"case when {left} = {getExp(exp.Arguments[0])} then 0 when {left} > {getExp(exp.Arguments[0])} then 1 else -1 end";
|
||||
case "Equals": return $"({left} = cast({getExp(exp.Arguments[0])} as string))";
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, ExpTSC tsc)
|
||||
{
|
||||
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
|
||||
switch (exp.Method.Name)
|
||||
{
|
||||
case "Abs": return $"abs({getExp(exp.Arguments[0])})";
|
||||
case "Sign": return $"sign({getExp(exp.Arguments[0])})";
|
||||
case "Floor": return $"floor({getExp(exp.Arguments[0])})";
|
||||
case "Ceiling": return $"ceiling({getExp(exp.Arguments[0])})";
|
||||
case "Round":
|
||||
if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32")
|
||||
return $"round({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
|
||||
return $"round({getExp(exp.Arguments[0])})";
|
||||
case "Exp": return $"exp({getExp(exp.Arguments[0])})";
|
||||
case "Log": return $"log({getExp(exp.Arguments[0])})";
|
||||
case "Log10": return $"log10({getExp(exp.Arguments[0])})";
|
||||
case "Pow": return $"pow({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
|
||||
case "Sqrt": return $"sqrt({getExp(exp.Arguments[0])})";
|
||||
case "Cos": return $"cos({getExp(exp.Arguments[0])})";
|
||||
case "Sin": return $"sin({getExp(exp.Arguments[0])})";
|
||||
case "Tan": return $"tan({getExp(exp.Arguments[0])})";
|
||||
case "Acos": return $"acos({getExp(exp.Arguments[0])})";
|
||||
case "Asin": return $"asin({getExp(exp.Arguments[0])})";
|
||||
case "Atan": return $"atan({getExp(exp.Arguments[0])})";
|
||||
case "Atan2": return $"atan2({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
|
||||
case "Truncate": return $"trunc({getExp(exp.Arguments[0])}, 0)";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, ExpTSC tsc)
|
||||
{
|
||||
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
|
||||
if (exp.Object == null)
|
||||
{
|
||||
switch (exp.Method.Name)
|
||||
{
|
||||
case "Compare": return $"datediff('s',{getExp(exp.Arguments[0])},{getExp(exp.Arguments[1])})";
|
||||
case "DaysInMonth": return $"days_in_month(to_date({getExp(exp.Arguments[0])} || '-' || {getExp(exp.Arguments[1])},'yyyy-MM'))";
|
||||
case "Equals": return $"({getExp(exp.Arguments[0])} = {getExp(exp.Arguments[1])})";
|
||||
case "IsLeapYear": return $"is_leap_year(to_date({getExp(exp.Arguments[0])},'yyyy'))";
|
||||
case "Parse": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"cast({getExp(exp.Arguments[0])} as timestamp)";
|
||||
case "ParseExact":
|
||||
case "TryParse":
|
||||
case "TryParseExact": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"cast({getExp(exp.Arguments[0])} as timestamp)";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var left = getExp(exp.Object);
|
||||
var args1 = exp.Arguments.Count == 0 ? null : getExp(exp.Arguments[0]);
|
||||
switch (exp.Method.Name)
|
||||
{
|
||||
case "Add": return $"dateadd('s',{args1},{left})";
|
||||
case "AddDays": return $"dateadd('d',{args1},{left})";
|
||||
case "AddHours": return $"dateadd('h',{args1},{left})";
|
||||
case "AddMilliseconds": return $"dateadd('s',{args1}/1000,{left})";
|
||||
case "AddMinutes": return $"dateadd('m',{args1},{left})";
|
||||
case "AddMonths": return $"dateadd('M',{args1},{left})";
|
||||
case "AddSeconds": return $"dateadd('s',{args1},{left})";
|
||||
case "AddTicks": return $"dateadd('s',{args1}/10000000,{left})";
|
||||
case "AddYears": return $"dateadd('y',{args1},{left})";
|
||||
case "Subtract":
|
||||
switch ((exp.Arguments[0].Type.IsNullableType() ? exp.Arguments[0].Type.GetGenericArguments().FirstOrDefault() : exp.Arguments[0].Type).FullName)
|
||||
{
|
||||
case "System.DateTime": return $"datediff('s',{args1},{left})";
|
||||
case "System.TimeSpan": return $"dateadd('s',({args1})*-1,{left})";
|
||||
}
|
||||
break;
|
||||
case "Equals": return $"({left} = cast({args1} as timestamp))";
|
||||
case "CompareTo": return $"datediff('s',{args1},{left})";
|
||||
case "ToString":
|
||||
if (left.EndsWith(" as timestamp)") == false) left = $"cast({left} as datetime)";
|
||||
if (exp.Arguments.Count == 0) return $"convert(varchar, {left}, 121)";
|
||||
switch (args1.TrimStart('N'))
|
||||
{
|
||||
case "'yyyy-MM-dd HH:mm:ss'": return $"convert(char(19), {left}, 120)";
|
||||
case "'yyyy-MM-dd HH:mm'": return $"substring(convert(char(19), {left}, 120), 1, 16)";
|
||||
case "'yyyy-MM-dd HH'": return $"substring(convert(char(19), {left}, 120), 1, 13)";
|
||||
case "'yyyy-MM-dd'": return $"convert(char(10), {left}, 23)";
|
||||
case "'yyyy-MM'": return $"substring(convert(char(10), {left}, 23), 1, 7)";
|
||||
case "'yyyyMMdd'": return $"convert(char(8), {left}, 112)";
|
||||
case "'yyyyMM'": return $"substring(convert(char(8), {left}, 112), 1, 6)";
|
||||
case "'yyyy'": return $"substring(convert(char(8), {left}, 112), 1, 4)";
|
||||
case "'HH:mm:ss'": return $"convert(char(8), {left}, 24)";
|
||||
}
|
||||
var isMatched = false;
|
||||
var nchar = args1.StartsWith("N'") ? "N" : "";
|
||||
args1 = Regex.Replace(args1, "(yyyy|yy|MM|M|dd|d|HH|H|hh|h|mm|m|ss|s|tt|t)", m =>
|
||||
{
|
||||
isMatched = true;
|
||||
switch (m.Groups[1].Value)
|
||||
{
|
||||
case "yyyy": return $"' + substring(convert(char(8), {left}, 112), 1, 4) + {nchar}'";
|
||||
case "yy": return $"' + substring(convert(char(6), {left}, 12), 1, 2) + {nchar}'";
|
||||
case "MM": return $"' + substring(convert(char(6), {left}, 12), 3, 2) + {nchar}'";
|
||||
case "M": return $"' + case when substring(convert(char(6), {left}, 12), 3, 1) = '0' then substring(convert(char(6), {left}, 12), 4, 1) else substring(convert(char(6), {left}, 12), 3, 2) end + {nchar}'";
|
||||
case "dd": return $"' + substring(convert(char(6), {left}, 12), 5, 2) + {nchar}'";
|
||||
case "d": return $"' + case when substring(convert(char(6), {left}, 12), 5, 1) = '0' then substring(convert(char(6), {left}, 12), 6, 1) else substring(convert(char(6), {left}, 12), 5, 2) end + {nchar}'";
|
||||
case "HH": return $"' + substring(convert(char(8), {left}, 24), 1, 2) + {nchar}'";
|
||||
case "H": return $"' + case when substring(convert(char(8), {left}, 24), 1, 1) = '0' then substring(convert(char(8), {left}, 24), 2, 1) else substring(convert(char(8), {left}, 24), 1, 2) end + {nchar}'";
|
||||
case "hh":
|
||||
return $"' + case cast(case when substring(convert(char(8), {left}, 24), 1, 1) = '0' then substring(convert(char(8), {left}, 24), 2, 1) else substring(convert(char(8), {left}, 24), 1, 2) end as int) % 12" +
|
||||
$"when 0 then '12' when 1 then '01' when 2 then '02' when 3 then '03' when 4 then '04' when 5 then '05' when 6 then '06' when 7 then '07' when 8 then '08' when 9 then '09' when 10 then '10' when 11 then '11' end + {nchar}'";
|
||||
case "h":
|
||||
return $"' + case cast(case when substring(convert(char(8), {left}, 24), 1, 1) = '0' then substring(convert(char(8), {left}, 24), 2, 1) else substring(convert(char(8), {left}, 24), 1, 2) end as int) % 12" +
|
||||
$"when 0 then '12' when 1 then '1' when 2 then '2' when 3 then '3' when 4 then '4' when 5 then '5' when 6 then '6' when 7 then '7' when 8 then '8' when 9 then '9' when 10 then '10' when 11 then '11' end + {nchar}'";
|
||||
case "mm": return $"' + substring(convert(char(8), {left}, 24), 4, 2) + {nchar}'";
|
||||
case "m": return $"' + case when substring(convert(char(8), {left}, 24), 4, 1) = '0' then substring(convert(char(8), {left}, 24), 5, 1) else substring(convert(char(8), {left}, 24), 4, 2) end + {nchar}'";
|
||||
case "ss": return $"' + substring(convert(char(8), {left}, 24), 7, 2) + {nchar}'";
|
||||
case "s": return $"' + case when substring(convert(char(8), {left}, 24), 7, 1) = '0' then substring(convert(char(8), {left}, 24), 8, 1) else substring(convert(char(8), {left}, 24), 7, 2) end + {nchar}'";
|
||||
case "tt": return $"' + case when cast(case when substring(convert(char(8), {left}, 24), 1, 1) = '0' then substring(convert(char(8), {left}, 24), 2, 1) else substring(convert(char(8), {left}, 24), 1, 2) end as int) >= 12 then 'PM' else 'AM' end + {nchar}'";
|
||||
case "t": return $"' + case when cast(case when substring(convert(char(8), {left}, 24), 1, 1) = '0' then substring(convert(char(8), {left}, 24), 2, 1) else substring(convert(char(8), {left}, 24), 1, 2) end as int) >= 12 then 'P' else 'A' end + {nchar}'";
|
||||
}
|
||||
return m.Groups[0].Value;
|
||||
});
|
||||
return isMatched == false ? args1 : $"({args1})";
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, ExpTSC tsc)
|
||||
{
|
||||
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
|
||||
if (exp.Object == null)
|
||||
{
|
||||
switch (exp.Method.Name)
|
||||
{
|
||||
case "Compare": return $"({getExp(exp.Arguments[0])}-({getExp(exp.Arguments[1])}))";
|
||||
case "Equals": return $"({getExp(exp.Arguments[0])} = {getExp(exp.Arguments[1])})";
|
||||
case "FromDays": return $"(({getExp(exp.Arguments[0])})*{60 * 60 * 24})";
|
||||
case "FromHours": return $"(({getExp(exp.Arguments[0])})*{60 * 60})";
|
||||
case "FromMilliseconds": return $"(({getExp(exp.Arguments[0])})/1000)";
|
||||
case "FromMinutes": return $"(({getExp(exp.Arguments[0])})*60)";
|
||||
case "FromSeconds": return $"({getExp(exp.Arguments[0])})";
|
||||
case "FromTicks": return $"(({getExp(exp.Arguments[0])})/10000000)";
|
||||
case "Parse": return $"cast({getExp(exp.Arguments[0])} as long)";
|
||||
case "ParseExact":
|
||||
case "TryParse":
|
||||
case "TryParseExact": return $"cast({getExp(exp.Arguments[0])} as long)";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var left = getExp(exp.Object);
|
||||
var args1 = exp.Arguments.Count == 0 ? null : getExp(exp.Arguments[0]);
|
||||
switch (exp.Method.Name)
|
||||
{
|
||||
case "Add": return $"({left}+{args1})";
|
||||
case "Subtract": return $"({left}-({args1}))";
|
||||
case "Equals": return $"({left} = {args1})";
|
||||
case "CompareTo": return $"({left}-({args1}))";
|
||||
case "ToString": return $"cast({left} as string)";
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, ExpTSC tsc)
|
||||
{
|
||||
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
|
||||
if (exp.Object == null)
|
||||
{
|
||||
switch (exp.Method.Name)
|
||||
{
|
||||
case "ToBoolean": return $"(cast({getExp(exp.Arguments[0])} as string) not in ('0','false','f','no'))";
|
||||
case "ToByte": return $"cast({getExp(exp.Arguments[0])} as byte)";
|
||||
case "ToChar": return $"left(cast({getExp(exp.Arguments[0])} as string), 1)";
|
||||
case "ToDateTime":
|
||||
return ExpressionConstDateTime(exp.Arguments[0]) ?? $"cast({getExp(exp.Arguments[0])} as timestamp)";
|
||||
case "ToDecimal": return $"cast({getExp(exp.Arguments[0])} as double)";
|
||||
case "ToDouble": return $"cast({getExp(exp.Arguments[0])} as double)";
|
||||
case "ToInt16": return $"cast({getExp(exp.Arguments[0])} as short)";
|
||||
case "ToInt32": return $"cast({getExp(exp.Arguments[0])} as int)";
|
||||
case "ToInt64": return $"cast({getExp(exp.Arguments[0])} as long)";
|
||||
case "ToSByte": return $"cast({getExp(exp.Arguments[0])} as byte)";
|
||||
case "ToSingle": return $"cast({getExp(exp.Arguments[0])} as int)";
|
||||
case "ToString": return $"cast({getExp(exp.Arguments[0])} as string)";
|
||||
case "ToUInt16": return $"cast({getExp(exp.Arguments[0])} as short)";
|
||||
case "ToUInt32": return $"cast({getExp(exp.Arguments[0])} as int)";
|
||||
case "ToUInt64": return $"cast({getExp(exp.Arguments[0])} as long)";
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class QuestDbExpressionVisitor : ExpressionVisitor
|
||||
{
|
||||
private List<string> list = new List<string>();
|
||||
|
||||
protected override Expression VisitMember(MemberExpression node)
|
||||
{
|
||||
list.Add(node.Member.Name);
|
||||
return node;
|
||||
}
|
||||
|
||||
internal string Fields()
|
||||
{
|
||||
var fileds = string.Join(",", list);
|
||||
list.Clear();
|
||||
return fileds;
|
||||
}
|
||||
}
|
||||
}
|
252
Providers/FreeSql.Provider.QuestDb/QuestDbFunctions.cs
Normal file
252
Providers/FreeSql.Provider.QuestDb/QuestDbFunctions.cs
Normal file
@ -0,0 +1,252 @@
|
||||
using FreeSql;
|
||||
using FreeSql.DataAnnotations;
|
||||
using FreeSql.Internal.CommonProvider;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
/// <summary>
|
||||
/// QuestDB lambda 表达式树扩展解析<para></para>
|
||||
/// https://questdb.io/docs/reference/function/aggregation/
|
||||
/// </summary>
|
||||
[ExpressionCall]
|
||||
public static class QuestFunc
|
||||
{
|
||||
public static ThreadLocal<ExpressionCallContext> expContext = new ThreadLocal<ExpressionCallContext>();
|
||||
static ExpressionCallContext ec => expContext.Value;
|
||||
static T call<T>(string rt)
|
||||
{
|
||||
ec.Result = rt;
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public static decimal avg(object value) => call<decimal>($"avg({ec.ParsedContent["value"]})");
|
||||
public static long count() => call<long>($"count(*)");
|
||||
public static long count(object column_name) => call<long>($"count({ec.ParsedContent["column_name"]})");
|
||||
public static long count_distinct(object column_name) => call<long>($"count_distinct({ec.ParsedContent["column_name"]})");
|
||||
public static string first(object column_name) => call<string>($"first({ec.ParsedContent["column_name"]})");
|
||||
public static string last(object column_name) => call<string>($"last({ec.ParsedContent["column_name"]})");
|
||||
public static decimal haversine_dist_deg(decimal lat, decimal lon, DateTime ts) => call<decimal>($"haversine_dist_deg({ec.ParsedContent["lat"]},{ec.ParsedContent["lon"]},{ec.ParsedContent["ts"]})");
|
||||
public static decimal ksum(object value) => call<decimal>($"ksum({ec.ParsedContent["value"]})");
|
||||
public static T max<T>(T value) => call<T>($"max({ec.ParsedContent["value"]})");
|
||||
public static T min<T>(T value) => call<T>($"min({ec.ParsedContent["value"]})");
|
||||
public static decimal nsum(object value) => call<decimal>($"nsum({ec.ParsedContent["value"]})");
|
||||
public static decimal stddev_samp(object value) => call<decimal>($"stddev_samp({ec.ParsedContent["value"]})");
|
||||
public static decimal sum(object value) => call<decimal>($"sum({ec.ParsedContent["value"]})");
|
||||
|
||||
public static bool isOrdered(object column) => call<bool>($"isOrdered({ec.ParsedContent["column"]})");
|
||||
public static T coalesce<T>(object value1, object value2) => call<T>($"coalesce({ec.ParsedContent["value1"]},{ec.ParsedContent["value2"]})");
|
||||
public static T coalesce<T>(object value1, object value2, object value3) => call<T>($"coalesce({ec.ParsedContent["value1"]},{ec.ParsedContent["value2"]},{ec.ParsedContent["value3"]})");
|
||||
public static T coalesce<T>(object value1, object value2, object value3, object value4) => call<T>($"coalesce({ec.ParsedContent["value1"]},{ec.ParsedContent["value2"]},{ec.ParsedContent["value3"]},{ec.ParsedContent["value4"]})");
|
||||
public static T coalesce<T>(object value1, object value2, object value3, object value4, object value5) => call<T>($"coalesce({ec.ParsedContent["value1"]},{ec.ParsedContent["value2"]},{ec.ParsedContent["value3"]},{ec.ParsedContent["value4"]},{ec.ParsedContent["value5"]})");
|
||||
public static T nullif<T>(object value1, object value2) => call<T>($"nullif({ec.ParsedContent["value1"]},{ec.ParsedContent["value2"]})");
|
||||
|
||||
public static DateTime date_trunc([RawValue] date_trunc_unit unit, object timestamp) => call<DateTime>($"date_trunc('{unit.ToString()}',{ec.ParsedContent["timestamp"]})");
|
||||
public enum date_trunc_unit
|
||||
{
|
||||
millennium,
|
||||
decade,
|
||||
century,
|
||||
year,
|
||||
quarter,
|
||||
month,
|
||||
week,
|
||||
day,
|
||||
hour,
|
||||
minute,
|
||||
second,
|
||||
milliseconds,
|
||||
microseconds,
|
||||
}
|
||||
public static DateTime dateadd([RawValue] date_period period, [RawValue] long n, object startDate) => call<DateTime>($"dateadd('{(char)(int)period}',{n},{ec.ParsedContent["startDate"]})");
|
||||
public static long datediff([RawValue] date_period period, object date1, object date2) => call<long>($"datediff('{(char)period}',{ec.ParsedContent["date1"]},{ec.ParsedContent["date2"]})");
|
||||
public enum date_period
|
||||
{
|
||||
second = 's',
|
||||
minute = 'm',
|
||||
hour = 'h',
|
||||
day = 'd',
|
||||
week = 'w',
|
||||
month = 'M',
|
||||
year = 'y',
|
||||
}
|
||||
public static int day(object timestamp) => call<int>($"day({ec.ParsedContent["timestamp"]})");
|
||||
public static int day_of_week(object timestamp) => call<int>($"day_of_week({ec.ParsedContent["timestamp"]})");
|
||||
public static int day_of_week_sunday_first(object timestamp) => call<int>($"day_of_week_sunday_first({ec.ParsedContent["timestamp"]})");
|
||||
public static long extract([RawValue] extract_unit unit, object timestamp) => call<int>($"extract({unit.ToString()} from {ec.ParsedContent["timestamp"]})");
|
||||
public enum extract_unit
|
||||
{
|
||||
millennium,
|
||||
epoch,
|
||||
decade,
|
||||
century,
|
||||
year,
|
||||
isoyear,
|
||||
/// <summary>
|
||||
/// day of year
|
||||
/// </summary>
|
||||
doy,
|
||||
quarter,
|
||||
month,
|
||||
week,
|
||||
/// <summary>
|
||||
/// day of week
|
||||
/// </summary>
|
||||
dow,
|
||||
isodow,
|
||||
day,
|
||||
hour,
|
||||
minute,
|
||||
second,
|
||||
microseconds,
|
||||
milliseconds,
|
||||
}
|
||||
public static int hour(object timestamp) => call<int>($"hour({ec.ParsedContent["timestamp"]})");
|
||||
public static bool is_leap_year(object timestamp) => call<bool>($"is_leap_year({ec.ParsedContent["timestamp"]})");
|
||||
public static bool days_in_month(object timestamp) => call<bool>($"days_in_month({ec.ParsedContent["timestamp"]})");
|
||||
public static int micros(object timestamp) => call<int>($"micros({ec.ParsedContent["timestamp"]})");
|
||||
public static int millis(object timestamp) => call<int>($"millis({ec.ParsedContent["timestamp"]})");
|
||||
public static int minute(object timestamp) => call<int>($"minute({ec.ParsedContent["timestamp"]})");
|
||||
public static int month(object timestamp) => call<int>($"month({ec.ParsedContent["timestamp"]})");
|
||||
public static DateTime now() => call<DateTime>($"now()");
|
||||
public static DateTime pg_postmaster_start_time() => call<DateTime>($"pg_postmaster_start_time()");
|
||||
public static int second(object timestamp) => call<int>($"second({ec.ParsedContent["timestamp"]})");
|
||||
/// <summary>
|
||||
/// Use now() with WHERE clause filter.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static DateTime systimestamp() => call<DateTime>($"systimestamp()");
|
||||
/// <summary>
|
||||
/// Use now() with WHERE clause filter.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static DateTime sysdate() => call<DateTime>($"sysdate()");
|
||||
|
||||
public static DateTime timestamp_ceil([RawValue] timestamp_ceil_unit unit, object timestamp) => call<DateTime>($"timestamp_ceil({(char)unit},{ec.ParsedContent["timestamp"]})");
|
||||
public static DateTime timestamp_floor([RawValue] timestamp_ceil_unit unit, object timestamp) => call<DateTime>($"timestamp_floor({(char)unit},{ec.ParsedContent["timestamp"]})");
|
||||
public enum timestamp_ceil_unit
|
||||
{
|
||||
milliseconds = 'T',
|
||||
seconds = 's',
|
||||
minutes = 'm',
|
||||
hours = 'h',
|
||||
days = 'd',
|
||||
months = 'M',
|
||||
year = 'y',
|
||||
}
|
||||
public static DateTime timestamp_shuffle(object timestamp_1, object timestamp_2) => call<DateTime>($"timestamp_shuffle({ec.ParsedContent["timestamp_1"]},{ec.ParsedContent["timestamp_2"]})");
|
||||
public static DateTime to_date(string str, string format) => call<DateTime>($"to_date({ec.ParsedContent["str"]},{ec.ParsedContent["format"]})");
|
||||
public static string to_str(DateTime value, string format) => call<string>($"to_str({ec.ParsedContent["value"]},{ec.ParsedContent["format"]})");
|
||||
public static DateTime to_timestamp(string str, string format) => call<DateTime>($"to_timestamp({ec.ParsedContent["str"]},{ec.ParsedContent["format"]})");
|
||||
public static DateTime to_timezone(DateTime timestamp, string timezone) => call<DateTime>($"to_timezone({ec.ParsedContent["timestamp"]},{ec.ParsedContent["timezone"]})");
|
||||
public static DateTime to_utc(DateTime timestamp, string timezone) => call<DateTime>($"to_utc({ec.ParsedContent["timestamp"]},{ec.ParsedContent["timezone"]})");
|
||||
public static int week_of_year(object timestamp) => call<int>($"week_of_year({ec.ParsedContent["timestamp"]})");
|
||||
public static int year(object timestamp) => call<int>($"year({ec.ParsedContent["timestamp"]})");
|
||||
|
||||
public static T abs<T>(T value) => call<T>($"abs({ec.ParsedContent["value"]})");
|
||||
public static decimal log(object value) => call<decimal>($"log({ec.ParsedContent["value"]})");
|
||||
public static decimal power(object _base, object exponent) => call<decimal>($"power({ec.ParsedContent["_base"]},{ec.ParsedContent["exponent"]})");
|
||||
public static T round<T>(T value, int scale) => call<T>($"round({ec.ParsedContent["value"]},{ec.ParsedContent["scale"]})");
|
||||
public static T round_down<T>(T value, int scale) => call<T>($"round_down({ec.ParsedContent["value"]},{ec.ParsedContent["scale"]})");
|
||||
public static T round_half_even<T>(T value, int scale) => call<T>($"round_half_even({ec.ParsedContent["value"]},{ec.ParsedContent["scale"]})");
|
||||
public static T round_up<T>(T value, int scale) => call<T>($"round_up({ec.ParsedContent["value"]},{ec.ParsedContent["scale"]})");
|
||||
public static string size_pretty(long value) => call<string>($"size_pretty({ec.ParsedContent["value"]})");
|
||||
public static decimal sqrt(object value) => call<decimal>($"sqrt({ec.ParsedContent["value"]})");
|
||||
|
||||
public static bool rnd_boolean() => call<bool>($"rnd_boolean()");
|
||||
public static byte rnd_byte() => call<byte>($"rnd_byte()");
|
||||
public static byte rnd_byte(byte min, byte max) => call<byte>($"rnd_byte({ec.ParsedContent["min"]},{ec.ParsedContent["max"]})");
|
||||
public static short rnd_short() => call<short>($"rnd_short()");
|
||||
public static short rnd_short(short min, short max) => call<short>($"rnd_short({ec.ParsedContent["min"]},{ec.ParsedContent["max"]})");
|
||||
public static int rnd_int() => call<int>($"rnd_int()");
|
||||
public static int rnd_int(int min, int max) => call<int>($"rnd_int({ec.ParsedContent["min"]},{ec.ParsedContent["max"]})");
|
||||
public static int rnd_int(int min, int max, int nanRate) => call<int>($"rnd_int({ec.ParsedContent["min"]},{ec.ParsedContent["max"]},{ec.ParsedContent["nanRate"]})");
|
||||
public static long rnd_long() => call<long>($"rnd_long()");
|
||||
public static long rnd_long(long min, long max) => call<long>($"rnd_long({ec.ParsedContent["min"]},{ec.ParsedContent["max"]})");
|
||||
public static long rnd_long(long min, long max, int nanRate) => call<long>($"rnd_long({ec.ParsedContent["min"]},{ec.ParsedContent["max"]},{ec.ParsedContent["nanRate"]})");
|
||||
public static BigInteger rnd_long256() => call<BigInteger>($"rnd_long256()");
|
||||
public static BigInteger rnd_long256(BigInteger min, BigInteger max) => call<BigInteger>($"rnd_long256({ec.ParsedContent["min"]},{ec.ParsedContent["max"]})");
|
||||
public static BigInteger rnd_long256(BigInteger min, BigInteger max, int nanRate) => call<BigInteger>($"rnd_long256({ec.ParsedContent["min"]},{ec.ParsedContent["max"]},{ec.ParsedContent["nanRate"]})");
|
||||
public static float rnd_float() => call<float>($"rnd_float()");
|
||||
public static float rnd_float(int nanRate) => call<float>($"rnd_float({ec.ParsedContent["nanRate"]})");
|
||||
public static double rnd_double() => call<double>($"rnd_double()");
|
||||
public static double rnd_double(int nanRate) => call<double>($"rnd_double({ec.ParsedContent["nanRate"]})");
|
||||
public static DateTime rnd_date(DateTime min, DateTime max) => call<DateTime>($"rnd_date({ec.ParsedContent["min"]},{ec.ParsedContent["max"]},0)");
|
||||
public static DateTime rnd_date(DateTime min, DateTime max, int nanRate) => call<DateTime>($"rnd_date({ec.ParsedContent["min"]},{ec.ParsedContent["max"]},{ec.ParsedContent["nanRate"]})");
|
||||
public static DateTime rnd_timestamp(DateTime min, DateTime max) => call<DateTime>($"rnd_timestamp({ec.ParsedContent["min"]},{ec.ParsedContent["max"]},0)");
|
||||
public static DateTime rnd_timestamp(DateTime min, DateTime max, int nanRate) => call<DateTime>($"rnd_timestamp({ec.ParsedContent["min"]},{ec.ParsedContent["max"]},{ec.ParsedContent["nanRate"]})");
|
||||
public static char rnd_char() => call<char>($"rnd_char()");
|
||||
public static string rnd_symbol([RawValue] string[] symbolList) => call<string>($"rnd_symbol({string.Join(",", symbolList.Select(a => ec.FormatSql(a)))})");
|
||||
public static string rnd_symbol(int list_size, int minLength, int maxLength, int nullRate) => call<string>($"rnd_symbol({ec.ParsedContent["list_size"]},{ec.ParsedContent["minLength"]},{ec.ParsedContent["maxLength"]},{ec.ParsedContent["nullRate"]})");
|
||||
public static string rnd_str([RawValue] string[] stringList) => call<string>($"rnd_str({string.Join(",", stringList.Select(a => ec.FormatSql(a)))})");
|
||||
public static string rnd_str(int list_size, int minLength, int maxLength, int nullRate) => call<string>($"rnd_str({ec.ParsedContent["list_size"]},{ec.ParsedContent["minLength"]},{ec.ParsedContent["maxLength"]},{ec.ParsedContent["nullRate"]})");
|
||||
public static byte[] rnd_bin() => call<byte[]>($"rnd_bin()");
|
||||
public static byte[] rnd_bin(long minBytes, int maxBytes, int nullRate) => call<byte[]>($"rnd_bin({ec.ParsedContent["minBytes"]},{ec.ParsedContent["maxBytes"]},{ec.ParsedContent["nullRate"]})");
|
||||
public static Guid rnd_uuid4() => call<Guid>($"rnd_uuid4()");
|
||||
|
||||
public static byte[] rnd_geohash(int bits) => call<byte[]>($"rnd_geohash({ec.ParsedContent["bits"]})");
|
||||
public static byte[] make_geohash(decimal lon, decimal lat, int bits) => call<byte[]>($"make_geohash({ec.ParsedContent["lon"]},{ec.ParsedContent["lat"]},{ec.ParsedContent["bits"]})");
|
||||
|
||||
public static string concat(object value1, object value2) => call<string>($"coalesce({ec.ParsedContent["value1"]},{ec.ParsedContent["value2"]})");
|
||||
public static string concat(object value1, object value2, object value3) => call<string>($"coalesce({ec.ParsedContent["value1"]},{ec.ParsedContent["value2"]},{ec.ParsedContent["value3"]})");
|
||||
public static string concat(object value1, object value2, object value3, object value4) => call<string>($"coalesce({ec.ParsedContent["value1"]},{ec.ParsedContent["value2"]},{ec.ParsedContent["value3"]},{ec.ParsedContent["value4"]})");
|
||||
public static string concat(object value1, object value2, object value3, object value4, object value5) => call<string>($"coalesce({ec.ParsedContent["value1"]},{ec.ParsedContent["value2"]},{ec.ParsedContent["value3"]},{ec.ParsedContent["value4"]},{ec.ParsedContent["value5"]})");
|
||||
public static string concat(object value1, object value2, object value3, object value4, object value5, object value6) => call<string>($"coalesce({ec.ParsedContent["value1"]},{ec.ParsedContent["value2"]},{ec.ParsedContent["value3"]},{ec.ParsedContent["value4"]},{ec.ParsedContent["value5"]},{ec.ParsedContent["value6"]})");
|
||||
public static string concat(object value1, object value2, object value3, object value4, object value5, object value6, object value7) => call<string>($"coalesce({ec.ParsedContent["value1"]},{ec.ParsedContent["value2"]},{ec.ParsedContent["value3"]},{ec.ParsedContent["value4"]},{ec.ParsedContent["value5"]},{ec.ParsedContent["value6"]},{ec.ParsedContent["value7"]})");
|
||||
public static string concat(object value1, object value2, object value3, object value4, object value5, object value6, object value7, object value8) => call<string>($"coalesce({ec.ParsedContent["value1"]},{ec.ParsedContent["value2"]},{ec.ParsedContent["value3"]},{ec.ParsedContent["value4"]},{ec.ParsedContent["value5"]},{ec.ParsedContent["value6"]},{ec.ParsedContent["value7"]},{ec.ParsedContent["value8"]})");
|
||||
public static string concat(object value1, object value2, object value3, object value4, object value5, object value6, object value7, object value8, object value9) => call<string>($"coalesce({ec.ParsedContent["value1"]},{ec.ParsedContent["value2"]},{ec.ParsedContent["value3"]},{ec.ParsedContent["value4"]},{ec.ParsedContent["value5"]},{ec.ParsedContent["value6"]},{ec.ParsedContent["value7"]},{ec.ParsedContent["value8"]},{ec.ParsedContent["value9"]})");
|
||||
public static string concat(object value1, object value2, object value3, object value4, object value5, object value6, object value7, object value8, object value9, object value10) => call<string>($"coalesce({ec.ParsedContent["value1"]},{ec.ParsedContent["value2"]},{ec.ParsedContent["value3"]},{ec.ParsedContent["value4"]},{ec.ParsedContent["value5"]},{ec.ParsedContent["value6"]},{ec.ParsedContent["value7"]},{ec.ParsedContent["value8"]},{ec.ParsedContent["value9"]},{ec.ParsedContent["value10"]})");
|
||||
public static long length(object value) => call<long>($"length({ec.ParsedContent["value"]})");
|
||||
public static string left(string str, int count) => call<string>($"left({ec.ParsedContent["str"]},{ec.ParsedContent["count"]})");
|
||||
public static string right(string str, int count) => call<string>($"right({ec.ParsedContent["str"]},{ec.ParsedContent["count"]})");
|
||||
public static int strpos(object str, string substr) => call<int>($"strpos({ec.ParsedContent["str"]},{ec.ParsedContent["substr"]})");
|
||||
public static string substring(string str, int start, int length) => call<string>($"substring({ec.ParsedContent["str"]},{ec.ParsedContent["start"]},{ec.ParsedContent["length"]})");
|
||||
public static string lower(string str) => call<string>($"lower({ec.ParsedContent["str"]})");
|
||||
public static string upper(string str) => call<string>($"upper({ec.ParsedContent["str"]})");
|
||||
|
||||
public static DateTime timestamp_sequence(DateTime startTimestamp, long step) => call<DateTime>($"timestamp_sequence({ec.ParsedContent["startTimestamp"]},{ec.ParsedContent["step"]})");
|
||||
public static string regexp_replace(string str1, string regex, string str2) => call<string>($"regexp_replace({ec.ParsedContent["str1"]},{ec.ParsedContent["regex"]},{ec.ParsedContent["str2"]})");
|
||||
public static bool regex_match(string str, string regex) => call<bool>($"{ec.ParsedContent["str"]} ~ {ec.ParsedContent["regex"]}");
|
||||
public static bool regex_not_match(string str, string regex) => call<bool>($"{ec.ParsedContent["str"]} !~ {ec.ParsedContent["regex"]}");
|
||||
public static bool like(string str, string pattern) => call<bool>($"{ec.ParsedContent["str"]} LIKE {ec.ParsedContent["pattern"]}");
|
||||
public static bool not_like(string str, string pattern) => call<bool>($"{ec.ParsedContent["str"]} NOT LIKE {ec.ParsedContent["pattern"]}");
|
||||
public static bool ilike(string str, string pattern) => call<bool>($"{ec.ParsedContent["str"]} ILIKE {ec.ParsedContent["pattern"]}");
|
||||
public static bool not_ilike(string str, string pattern) => call<bool>($"{ec.ParsedContent["str"]} NOT ILIKE {ec.ParsedContent["pattern"]}");
|
||||
|
||||
public static bool within(object geo, object geohash1) => call<bool>($"{ec.ParsedContent["str"]} within({ec.ParsedContent["geohash1"]})");
|
||||
public static bool within(object geo, object geohash1, object geohash2) => call<bool>($"{ec.ParsedContent["str"]} within({ec.ParsedContent["geohash1"]},{ec.ParsedContent["geohash2"]})");
|
||||
public static bool within(object geo, object geohash1, object geohash2, object geohash3) => call<bool>($"{ec.ParsedContent["str"]} within({ec.ParsedContent["geohash1"]},{ec.ParsedContent["geohash2"]},{ec.ParsedContent["geohash3"]})");
|
||||
public static bool within(object geo, object geohash1, object geohash2, object geohash3, object geohash4) => call<bool>($"{ec.ParsedContent["str"]} within({ec.ParsedContent["geohash1"]},{ec.ParsedContent["geohash2"]},{ec.ParsedContent["geohash3"]},{ec.ParsedContent["geohash4"]})");
|
||||
public static bool within(object geo, object geohash1, object geohash2, object geohash3, object geohash4, object geohash5) => call<bool>($"{ec.ParsedContent["str"]} within({ec.ParsedContent["geohash1"]},{ec.ParsedContent["geohash2"]},{ec.ParsedContent["geohash3"]},{ec.ParsedContent["geohash4"]},{ec.ParsedContent["geohash5"]})");
|
||||
}
|
||||
|
||||
partial class QuestDbGlobalExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// QuestDB lambda 表达式树扩展解析<para></para>
|
||||
/// fsql.SelectLongSequence(10, () => new { str1 = qdbfunc.rnd_str(10, 5, 8, 0), ... })...<para></para>
|
||||
/// SELECT rnd_str(10,5,8,0) FROM long_sequence(10)
|
||||
/// </summary>
|
||||
public static ISelect<T> SelectLongSequence<T>(this IFreeSql fsql, long iterations, Expression<Func<T>> selector)
|
||||
{
|
||||
var selector2 = Expression.Lambda<Func<object, T>>(selector.Body, Expression.Parameter(typeof(object), "a"));
|
||||
var tablename = $"(long_sequence ({iterations}))";
|
||||
return fsql.Select<object>().AsTable((t, old) => tablename).WithTempQuery(selector2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// QuestDB lambda 表达式树扩展解析<para></para>
|
||||
/// fsql.SelectTimestampSequence(10, () => new { str1 = qdbfunc.rnd_str(10, 5, 8, 0), ... })...<para></para>
|
||||
/// SELECT rnd_str(10,5,8,0) FROM long_sequence(10)
|
||||
/// </summary>
|
||||
public static ISelect<T> SelectTimestampSequence<T>(this IFreeSql fsql, DateTime startTimestamp, TimeSpan step, Expression<Func<T>> selector)
|
||||
{
|
||||
var selector2 = Expression.Lambda<Func<object, T>>(selector.Body, Expression.Parameter(typeof(object), "a"));
|
||||
var tablename = $"(timestamp_sequence (to_timestamp('{startTimestamp.ToString("yyyy-MM-dd HH:mm:ss")}', 'yyyy-MM-dd HH:mm:ss'), {Math.Ceiling(step.TotalMilliseconds / 1000)}))";
|
||||
return fsql.Select<object>().AsTable((t, old) => tablename).WithTempQuery(selector2);
|
||||
}
|
||||
}
|
349
Providers/FreeSql.Provider.QuestDb/QuestDbGlobalExtensions.cs
Normal file
349
Providers/FreeSql.Provider.QuestDb/QuestDbGlobalExtensions.cs
Normal file
@ -0,0 +1,349 @@
|
||||
using CsvHelper;
|
||||
using FreeSql;
|
||||
using FreeSql.Internal.CommonProvider;
|
||||
using FreeSql.Internal.Model;
|
||||
using FreeSql.QuestDb;
|
||||
using FreeSql.QuestDb.Curd;
|
||||
using Newtonsoft.Json;
|
||||
using Npgsql;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using FreeSql.Provider.QuestDb;
|
||||
using System.Net;
|
||||
|
||||
public static partial class QuestDbGlobalExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换
|
||||
/// </summary>
|
||||
/// <param name="that"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
public static string FormatQuestDb(this string that, params object[] args) =>
|
||||
_questDbAdo.Addslashes(that, args);
|
||||
|
||||
private static readonly QuestDbAdo _questDbAdo = new QuestDbAdo();
|
||||
|
||||
public static FreeSqlBuilder UseQuestDbRestAPI(this FreeSqlBuilder build, string host, string username = "",
|
||||
string password = "") => RestAPIExtension.UseQuestDbRestAPI(build, host, username, password);
|
||||
|
||||
/// <summary>
|
||||
/// 对于多个时间序列存储在同一个表中的场景,根据时间戳检索给定键或键组合的最新项。
|
||||
/// </summary>
|
||||
/// <typeparam name="T1"></typeparam>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <param name="select"></param>
|
||||
/// <param name="timestamp">时间标识</param>
|
||||
/// <param name="partition">最新项的列</param>
|
||||
/// <returns></returns>
|
||||
public static ISelect<T1> LatestOn<T1, TKey>(this ISelect<T1> select, Expression<Func<T1, DateTime?>> timestamp,
|
||||
Expression<Func<T1, TKey>> partition)
|
||||
{
|
||||
LatestOnExtension.InternelImpl(timestamp, partition);
|
||||
return select;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对于多个时间序列存储在同一个表中的场景,根据时间戳检索给定键或键组合的最新项。
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <param name="select"></param>
|
||||
/// <param name="timestamp">时间标识</param>
|
||||
/// <param name="partition">最新项的列</param>
|
||||
/// <returns></returns>
|
||||
public static ISelect<T1, T2> LatestOn<T1, T2, TKey>(this ISelect<T1, T2> select,
|
||||
Expression<Func<T1, DateTime?>> timestamp,
|
||||
Expression<Func<T1, TKey>> partition) where T2 : class
|
||||
{
|
||||
LatestOnExtension.InternelImpl(timestamp, partition);
|
||||
return select;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对于多个时间序列存储在同一个表中的场景,根据时间戳检索给定键或键组合的最新项。
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <param name="select"></param>
|
||||
/// <param name="timestamp">时间标识</param>
|
||||
/// <param name="partition">最新项的列</param>
|
||||
/// <returns></returns>
|
||||
public static ISelect<T1, T2, T3> LatestOn<T1, T2, T3, TKey>(this ISelect<T1, T2, T3> select,
|
||||
Expression<Func<T1, DateTime?>> timestamp,
|
||||
Expression<Func<T1, TKey>> partition) where T2 : class where T3 : class
|
||||
{
|
||||
LatestOnExtension.InternelImpl(timestamp, partition);
|
||||
return select;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对于多个时间序列存储在同一个表中的场景,根据时间戳检索给定键或键组合的最新项。
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <param name="select"></param>
|
||||
/// <param name="timestamp">时间标识</param>
|
||||
/// <param name="partition">最新项的列</param>
|
||||
/// <returns></returns>
|
||||
public static ISelect<T1, T2, T3, T4> LatestOn<T1, T2, T3, T4, TKey>(this ISelect<T1, T2, T3, T4> select,
|
||||
Expression<Func<T1, DateTime?>> timestamp,
|
||||
Expression<Func<T1, TKey>> partition) where T2 : class where T3 : class where T4 : class
|
||||
{
|
||||
LatestOnExtension.InternelImpl(timestamp, partition);
|
||||
return select;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SAMPLE BY用于时间序列数据,将大型数据集汇总为同质时间块的聚合,作为SELECT语句的一部分。对缺少数据的数据集执行查询的用户可以使用FILL关键字指定填充行为
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="select"></param>
|
||||
/// <param name="time">时长</param>
|
||||
/// <param name="unit">单位</param>
|
||||
/// <param name="alignToCalendar">对准日历</param>
|
||||
/// <returns></returns>
|
||||
public static ISelect<T> SampleBy<T>(this ISelect<T> select, double time, SampleUnit unit,
|
||||
bool alignToCalendar = false)
|
||||
{
|
||||
SampleByExtension.IsExistence.Value = true;
|
||||
var samoleByTemple = $"{Environment.NewLine}SAMPLE BY {{0}}{{1}} {{2}}";
|
||||
string alignToCalendarTemple = "";
|
||||
if (alignToCalendar) alignToCalendarTemple = "ALIGN TO CALENDAR ";
|
||||
SampleByExtension.SamoleByString.Value =
|
||||
string.Format(samoleByTemple, time.ToString(), (char)unit, alignToCalendarTemple);
|
||||
return select;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 逐行读取,包含空行
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
private static List<string> SplitByLine(string text)
|
||||
{
|
||||
List<string> lines = new List<string>();
|
||||
byte[] array = Encoding.UTF8.GetBytes(text);
|
||||
using (MemoryStream stream = new MemoryStream(array))
|
||||
{
|
||||
using (var sr = new StreamReader(stream))
|
||||
{
|
||||
string line = sr.ReadLine();
|
||||
while (line != null)
|
||||
{
|
||||
lines.Add(line);
|
||||
line = sr.ReadLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量快速插入
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="that"></param>
|
||||
/// <param name="dateFormat">导入时,时间格式 默认:yyyy/M/d H:mm:ss</param>
|
||||
/// <returns></returns>
|
||||
public static async Task<int> ExecuteQuestDbBulkCopyAsync<T>(this IInsert<T> that,
|
||||
string dateFormat = "yyyy/M/d H:mm:ss") where T : class
|
||||
{
|
||||
//思路:通过提供的RestAPI imp,实现快速复制
|
||||
if (string.IsNullOrWhiteSpace(RestAPIExtension.BaseUrl))
|
||||
{
|
||||
throw new Exception(
|
||||
"BulkCopy功能需要启用RestAPI,启用方式:new FreeSqlBuilder().UseQuestDbRestAPI(\"localhost:9000\", \"username\", \"password\")");
|
||||
}
|
||||
|
||||
var result = 0;
|
||||
|
||||
try
|
||||
{
|
||||
var client = QuestDbContainer.GetService<IHttpClientFactory>().CreateClient();
|
||||
var boundary = "---------------" + DateTime.Now.Ticks.ToString("x");
|
||||
var list = new List<Hashtable>();
|
||||
var insert = that as QuestDbInsert<T>;
|
||||
var name = insert.InternalTableRuleInvoke(); //获取表名
|
||||
insert.InternalOrm.DbFirst.GetTableByName(name).Columns.ForEach(d =>
|
||||
{
|
||||
if (d.DbTypeText == "TIMESTAMP")
|
||||
{
|
||||
list.Add(new Hashtable()
|
||||
{
|
||||
{ "name", d.Name },
|
||||
{ "type", d.DbTypeText },
|
||||
{ "pattern", dateFormat }
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(new Hashtable()
|
||||
{
|
||||
{ "name", d.Name },
|
||||
{ "type", d.DbTypeText }
|
||||
});
|
||||
}
|
||||
});
|
||||
var schema = JsonConvert.SerializeObject(list);
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
//写入CSV文件
|
||||
using (var writer = new StreamWriter(stream))
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.CurrentCulture))
|
||||
{
|
||||
await csv.WriteRecordsAsync(insert._source);
|
||||
}
|
||||
|
||||
var httpContent = new MultipartFormDataContent(boundary);
|
||||
if (!string.IsNullOrWhiteSpace(RestAPIExtension.authorization))
|
||||
client.DefaultRequestHeaders.Add("Authorization", RestAPIExtension.authorization);
|
||||
httpContent.Add(new StringContent(schema), "schema");
|
||||
httpContent.Add(new ByteArrayContent(stream.ToArray()), "data");
|
||||
//boundary带双引号 可能导致服务器错误情况
|
||||
httpContent.Headers.Remove("Content-Type");
|
||||
httpContent.Headers.TryAddWithoutValidation("Content-Type",
|
||||
"multipart/form-data; boundary=" + boundary);
|
||||
var httpResponseMessage =
|
||||
await client.PostAsync($"{RestAPIExtension.BaseUrl}/imp?name={name}", httpContent);
|
||||
var readAsStringAsync = await httpResponseMessage.Content.ReadAsStringAsync();
|
||||
var splitByLine = SplitByLine(readAsStringAsync);
|
||||
foreach (var s in splitByLine)
|
||||
{
|
||||
if (s.Contains("Rows"))
|
||||
{
|
||||
var strings = s.Split('|');
|
||||
if (strings[1].Trim() == "Rows imported")
|
||||
{
|
||||
result = Convert.ToInt32(strings[2].Trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量快速插入
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="insert"></param>
|
||||
/// <param name="dateFormat">导入时,时间格式 默认:yyyy/M/d H:mm:ss</param>
|
||||
/// <returns></returns>
|
||||
public static int ExecuteQuestDbBulkCopy<T>(this IInsert<T> insert, string dateFormat = "yyyy/M/d H:mm:ss") where T : class
|
||||
{
|
||||
return ExecuteQuestDbBulkCopyAsync(insert, dateFormat).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
static class SampleByExtension
|
||||
{
|
||||
//是否使用该方法
|
||||
internal static AsyncLocal<bool> IsExistence = new AsyncLocal<bool>()
|
||||
{
|
||||
Value = false
|
||||
};
|
||||
|
||||
internal static AsyncLocal<string> SamoleByString = new AsyncLocal<string>()
|
||||
{
|
||||
Value = string.Empty
|
||||
};
|
||||
|
||||
internal static void Initialize()
|
||||
{
|
||||
IsExistence.Value = false;
|
||||
SamoleByString.Value = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
static class LatestOnExtension
|
||||
{
|
||||
//是否使用该方法
|
||||
internal static AsyncLocal<bool> IsExistence = new AsyncLocal<bool>()
|
||||
{
|
||||
Value = false
|
||||
};
|
||||
|
||||
internal static AsyncLocal<string> LatestOnString = new AsyncLocal<string>()
|
||||
{
|
||||
Value = string.Empty
|
||||
};
|
||||
|
||||
internal static void Initialize()
|
||||
{
|
||||
IsExistence.Value = false;
|
||||
LatestOnString.Value = string.Empty;
|
||||
}
|
||||
|
||||
internal static void InternelImpl<T1, TKey>(Expression<Func<T1, DateTime?>> timestamp,
|
||||
Expression<Func<T1, TKey>> partition)
|
||||
{
|
||||
IsExistence.Value = true;
|
||||
var latestOnTemple = $"{Environment.NewLine}LATEST ON {{0}} PARTITION BY {{1}} ";
|
||||
var expressionVisitor = new QuestDbExpressionVisitor();
|
||||
expressionVisitor.Visit(timestamp);
|
||||
var _timestamp = expressionVisitor.Fields();
|
||||
expressionVisitor.Visit(partition);
|
||||
var _partition = expressionVisitor.Fields();
|
||||
LatestOnString.Value = string.Format(latestOnTemple, _timestamp, _partition);
|
||||
}
|
||||
}
|
||||
|
||||
static class RestAPIExtension
|
||||
{
|
||||
internal static string BaseUrl = string.Empty;
|
||||
internal static string authorization = string.Empty;
|
||||
|
||||
internal static async Task<string> ExecAsync(string sql)
|
||||
{
|
||||
//HTTP GET 执行SQL
|
||||
var result = string.Empty;
|
||||
var client = QuestDbContainer.GetService<IHttpClientFactory>().CreateClient();
|
||||
var url = $"{BaseUrl}/exec?query={HttpUtility.UrlEncode(sql)}";
|
||||
if (!string.IsNullOrWhiteSpace(authorization))
|
||||
client.DefaultRequestHeaders.Add("Authorization", authorization);
|
||||
var httpResponseMessage = await client.GetAsync(url);
|
||||
result = await httpResponseMessage.Content.ReadAsStringAsync();
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static FreeSqlBuilder UseQuestDbRestAPI(FreeSqlBuilder buider, string host, string username = "",
|
||||
string password = "")
|
||||
{
|
||||
BaseUrl = host;
|
||||
if (BaseUrl.EndsWith("/"))
|
||||
BaseUrl = BaseUrl.Remove(BaseUrl.Length - 1);
|
||||
|
||||
if (!BaseUrl.ToLower().StartsWith("http"))
|
||||
BaseUrl = $"http://{BaseUrl}";
|
||||
//生成TOKEN
|
||||
if (!string.IsNullOrWhiteSpace(username) && !string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}"));
|
||||
authorization = $"Basic {base64}";
|
||||
}
|
||||
|
||||
//RestApi需要无参数
|
||||
buider.UseNoneCommandParameter(true);
|
||||
return buider;
|
||||
}
|
||||
}
|
175
Providers/FreeSql.Provider.QuestDb/QuestDbProvider.cs
Normal file
175
Providers/FreeSql.Provider.QuestDb/QuestDbProvider.cs
Normal file
@ -0,0 +1,175 @@
|
||||
using FreeSql.Internal;
|
||||
using FreeSql.Internal.CommonProvider;
|
||||
using FreeSql.Provider.QuestDb;
|
||||
using FreeSql.QuestDb.Curd;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NpgsqlTypes;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Linq.Expressions;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace FreeSql.QuestDb
|
||||
{
|
||||
public class QuestDbProvider<TMark> : BaseDbProvider, IFreeSql<TMark>
|
||||
{
|
||||
static int _firstInit = 1;
|
||||
static void InitInternal()
|
||||
{
|
||||
if (Interlocked.Exchange(ref _firstInit, 0) == 1) //不能放在 static ctor .NetFramework 可能报初始化类型错误
|
||||
{
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(BigInteger)] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(BitArray)] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlPoint)] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlLine)] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlLSeg)] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlBox)] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlPath)] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlPolygon)] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlCircle)] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof((IPAddress Address, int Subnet))] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(IPAddress)] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PhysicalAddress)] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlRange<int>)] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlRange<long>)] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlRange<decimal>)] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlRange<DateTime>)] = true;
|
||||
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(Dictionary<string, string>)] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(JToken)] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(JObject)] = true;
|
||||
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(JArray)] = true;
|
||||
|
||||
var MethodJTokenFromObject = typeof(JToken).GetMethod("FromObject", new[] { typeof(object) });
|
||||
var MethodJObjectFromObject = typeof(JObject).GetMethod("FromObject", new[] { typeof(object) });
|
||||
var MethodJArrayFromObject = typeof(JArray).GetMethod("FromObject", new[] { typeof(object) });
|
||||
var MethodJTokenParse = typeof(JToken).GetMethod("Parse", new[] { typeof(string) });
|
||||
var MethodJObjectParse = typeof(JObject).GetMethod("Parse", new[] { typeof(string) });
|
||||
var MethodJArrayParse = typeof(JArray).GetMethod("Parse", new[] { typeof(string) });
|
||||
var MethodJsonConvertDeserializeObject =
|
||||
typeof(JsonConvert).GetMethod("DeserializeObject", new[] { typeof(string), typeof(Type) });
|
||||
var MethodToString = typeof(Utils).GetMethod("ToStringConcat", BindingFlags.Public | BindingFlags.Static,
|
||||
null, new[] { typeof(object) }, null);
|
||||
Utils.GetDataReaderValueBlockExpressionSwitchTypeFullName.Add(
|
||||
(LabelTarget returnTarget, Expression valueExp, Type type) =>
|
||||
{
|
||||
switch (type.FullName)
|
||||
{
|
||||
case "Newtonsoft.Json.Linq.JToken":
|
||||
return Expression.IfThenElse(
|
||||
Expression.TypeIs(valueExp, typeof(string)),
|
||||
Expression.Return(returnTarget,
|
||||
Expression.TypeAs(
|
||||
Expression.Call(MethodJTokenParse,
|
||||
Expression.Convert(valueExp, typeof(string))), typeof(JToken))),
|
||||
Expression.Return(returnTarget,
|
||||
Expression.TypeAs(Expression.Call(MethodJTokenFromObject, valueExp),
|
||||
typeof(JToken))));
|
||||
case "Newtonsoft.Json.Linq.JObject":
|
||||
return Expression.IfThenElse(
|
||||
Expression.TypeIs(valueExp, typeof(string)),
|
||||
Expression.Return(returnTarget,
|
||||
Expression.TypeAs(
|
||||
Expression.Call(MethodJObjectParse,
|
||||
Expression.Convert(valueExp, typeof(string))), typeof(JObject))),
|
||||
Expression.Return(returnTarget,
|
||||
Expression.TypeAs(Expression.Call(MethodJObjectFromObject, valueExp),
|
||||
typeof(JObject))));
|
||||
case "Newtonsoft.Json.Linq.JArray":
|
||||
return Expression.IfThenElse(
|
||||
Expression.TypeIs(valueExp, typeof(string)),
|
||||
Expression.Return(returnTarget,
|
||||
Expression.TypeAs(
|
||||
Expression.Call(MethodJArrayParse,
|
||||
Expression.Convert(valueExp, typeof(string))), typeof(JArray))),
|
||||
Expression.Return(returnTarget,
|
||||
Expression.TypeAs(Expression.Call(MethodJArrayFromObject, valueExp),
|
||||
typeof(JArray))));
|
||||
case "Npgsql.LegacyPostgis.PostgisGeometry":
|
||||
return Expression.Return(returnTarget, valueExp);
|
||||
case "NetTopologySuite.Geometries.Geometry":
|
||||
return Expression.Return(returnTarget, valueExp);
|
||||
}
|
||||
|
||||
if (typeof(IList).IsAssignableFrom(type))
|
||||
return Expression.IfThenElse(
|
||||
Expression.TypeIs(valueExp, typeof(string)),
|
||||
Expression.Return(returnTarget,
|
||||
Expression.TypeAs(
|
||||
Expression.Call(MethodJsonConvertDeserializeObject,
|
||||
Expression.Convert(valueExp, typeof(string)),
|
||||
Expression.Constant(type, typeof(Type))), type)),
|
||||
Expression.Return(returnTarget,
|
||||
Expression.TypeAs(
|
||||
Expression.Call(MethodJsonConvertDeserializeObject,
|
||||
Expression.Convert(Expression.Call(MethodToString, valueExp), typeof(string)),
|
||||
Expression.Constant(type, typeof(Type))), type)));
|
||||
return null;
|
||||
});
|
||||
|
||||
Select0Provider._dicMethodDataReaderGetValue[typeof(Guid)] =
|
||||
typeof(DbDataReader).GetMethod("GetGuid", new Type[] { typeof(int) });
|
||||
|
||||
QuestDbContainer.Initialize(service =>
|
||||
{
|
||||
service.AddHttpClient();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override ISelect<T1> CreateSelectProvider<T1>(object dywhere) =>
|
||||
new QuestDbSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||
|
||||
public override IInsert<T1> CreateInsertProvider<T1>() =>
|
||||
new QuestDbInsert<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
|
||||
|
||||
public override IUpdate<T1> CreateUpdateProvider<T1>(object dywhere) =>
|
||||
new QuestDbUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||
|
||||
public override IDelete<T1> CreateDeleteProvider<T1>(object dywhere) =>
|
||||
new QuestDbDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||
|
||||
public override IInsertOrUpdate<T1> CreateInsertOrUpdateProvider<T1>() =>
|
||||
new QuestDbInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
|
||||
|
||||
public QuestDbProvider(string masterConnectionString, string[] slaveConnectionString,
|
||||
Func<DbConnection> connectionFactory = null)
|
||||
{
|
||||
InitInternal();
|
||||
this.InternalCommonUtils = new QuestDbUtils(this);
|
||||
this.InternalCommonExpression = new QuestDbExpression(this.InternalCommonUtils);
|
||||
|
||||
this.Ado = new QuestDbAdo(this.InternalCommonUtils, masterConnectionString, slaveConnectionString,
|
||||
connectionFactory);
|
||||
this.Aop = new AopProvider();
|
||||
|
||||
this.DbFirst = new QuestDbDbFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
|
||||
this.CodeFirst = new QuestDbCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
|
||||
|
||||
//this.Aop.AuditDataReader += (_, e) =>
|
||||
//{
|
||||
// var dbtype = e.DataReader.GetDataTypeName(e.Index);
|
||||
// var m = Regex.Match(dbtype, @"numeric\((\d+)\)", RegexOptions.IgnoreCase);
|
||||
// if (m.Success && int.Parse(m.Groups[1].Value) > 19)
|
||||
// e.Value = e.DataReader.GetFieldValue<BigInteger>(e.Index);
|
||||
//};
|
||||
}
|
||||
|
||||
~QuestDbProvider() => this.Dispose();
|
||||
int _disposeCounter;
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (Interlocked.Increment(ref _disposeCounter) != 1) return;
|
||||
(this.Ado as AdoProvider)?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
315
Providers/FreeSql.Provider.QuestDb/QuestDbUtils.cs
Normal file
315
Providers/FreeSql.Provider.QuestDb/QuestDbUtils.cs
Normal file
@ -0,0 +1,315 @@
|
||||
using FreeSql.Internal;
|
||||
using FreeSql.Internal.Model;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Npgsql;
|
||||
using NpgsqlTypes;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using FreeSql.QuestDb;
|
||||
using System.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using System.IO;
|
||||
using CsvHelper;
|
||||
|
||||
namespace FreeSql.QuestDb
|
||||
{
|
||||
class QuestDbUtils : CommonUtils
|
||||
{
|
||||
string now_to_timezone;
|
||||
public QuestDbUtils(IFreeSql orm) : base(orm)
|
||||
{
|
||||
var timeOffset = (int)DateTime.Now.Subtract(DateTime.UtcNow).TotalMinutes;
|
||||
if (timeOffset == 0) now_to_timezone = "systimestamp()";
|
||||
else
|
||||
{
|
||||
var absTimeOffset = Math.Abs(timeOffset);
|
||||
now_to_timezone = $"to_timezone(systimestamp(),'{(timeOffset > 0 ? '+' : '-')}{(absTimeOffset / 60).ToString().PadLeft(2, '0')}:{(absTimeOffset % 60).ToString().PadLeft(2, '0')}')";
|
||||
}
|
||||
}
|
||||
|
||||
static Array getParamterArrayValue(Type arrayType, object value, object defaultValue)
|
||||
{
|
||||
var valueArr = value as Array;
|
||||
var len = valueArr.GetLength(0);
|
||||
var ret = Array.CreateInstance(arrayType, len);
|
||||
for (var a = 0; a < len; a++)
|
||||
{
|
||||
var item = valueArr.GetValue(a);
|
||||
ret.SetValue(item == null ? defaultValue : getParamterValue(item.GetType(), item, 1), a);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Dictionary<string, Func<object, object>> dicGetParamterValue =
|
||||
new Dictionary<string, Func<object, object>>
|
||||
{
|
||||
{ typeof(JToken).FullName, a => string.Concat(a) },
|
||||
{ typeof(JToken[]).FullName, a => getParamterArrayValue(typeof(string), a, null) },
|
||||
{ typeof(JObject).FullName, a => string.Concat(a) },
|
||||
{ typeof(JObject[]).FullName, a => getParamterArrayValue(typeof(string), a, null) },
|
||||
{ typeof(JArray).FullName, a => string.Concat(a) },
|
||||
{ typeof(JArray[]).FullName, a => getParamterArrayValue(typeof(string), a, null) },
|
||||
{ typeof(uint).FullName, a => long.Parse(string.Concat(a)) },
|
||||
{ typeof(uint[]).FullName, a => getParamterArrayValue(typeof(long), a, 0) },
|
||||
{ typeof(uint?[]).FullName, a => getParamterArrayValue(typeof(long?), a, null) },
|
||||
{ typeof(ulong).FullName, a => decimal.Parse(string.Concat(a)) },
|
||||
{ typeof(ulong[]).FullName, a => getParamterArrayValue(typeof(decimal), a, 0) },
|
||||
{ typeof(ulong?[]).FullName, a => getParamterArrayValue(typeof(decimal?), a, null) },
|
||||
{ typeof(ushort).FullName, a => int.Parse(string.Concat(a)) },
|
||||
{ typeof(ushort[]).FullName, a => getParamterArrayValue(typeof(int), a, 0) },
|
||||
{ typeof(ushort?[]).FullName, a => getParamterArrayValue(typeof(int?), a, null) },
|
||||
{ typeof(byte).FullName, a => short.Parse(string.Concat(a)) },
|
||||
{ typeof(byte[]).FullName, a => getParamterArrayValue(typeof(short), a, 0) },
|
||||
{ typeof(byte?[]).FullName, a => getParamterArrayValue(typeof(short?), a, null) },
|
||||
{ typeof(sbyte).FullName, a => short.Parse(string.Concat(a)) },
|
||||
{ typeof(sbyte[]).FullName, a => getParamterArrayValue(typeof(short), a, 0) },
|
||||
{ typeof(sbyte?[]).FullName, a => getParamterArrayValue(typeof(short?), a, null) },
|
||||
{ typeof(char).FullName, a => string.Concat(a).Replace('\0', ' ').ToCharArray().FirstOrDefault() },
|
||||
{
|
||||
typeof(BigInteger).FullName,
|
||||
a => BigInteger.Parse(string.Concat(a), System.Globalization.NumberStyles.Any)
|
||||
},
|
||||
{ typeof(BigInteger[]).FullName, a => getParamterArrayValue(typeof(BigInteger), a, 0) },
|
||||
{ typeof(BigInteger?[]).FullName, a => getParamterArrayValue(typeof(BigInteger?), a, null) },
|
||||
|
||||
{
|
||||
typeof(NpgsqlPath).FullName, a =>
|
||||
{
|
||||
var path = (NpgsqlPath)a;
|
||||
try
|
||||
{
|
||||
int count = path.Count;
|
||||
return path;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new NpgsqlPath(new NpgsqlPoint(0, 0));
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
typeof(NpgsqlPath[]).FullName,
|
||||
a => getParamterArrayValue(typeof(NpgsqlPath), a, new NpgsqlPath(new NpgsqlPoint(0, 0)))
|
||||
},
|
||||
{ typeof(NpgsqlPath?[]).FullName, a => getParamterArrayValue(typeof(NpgsqlPath?), a, null) },
|
||||
|
||||
{
|
||||
typeof(NpgsqlPolygon).FullName, a =>
|
||||
{
|
||||
var polygon = (NpgsqlPolygon)a;
|
||||
try
|
||||
{
|
||||
int count = polygon.Count;
|
||||
return polygon;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new NpgsqlPolygon(new NpgsqlPoint(0, 0), new NpgsqlPoint(0, 0));
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
typeof(NpgsqlPolygon[]).FullName,
|
||||
a => getParamterArrayValue(typeof(NpgsqlPolygon), a,
|
||||
new NpgsqlPolygon(new NpgsqlPoint(0, 0), new NpgsqlPoint(0, 0)))
|
||||
},
|
||||
{ typeof(NpgsqlPolygon?[]).FullName, a => getParamterArrayValue(typeof(NpgsqlPolygon?), a, null) },
|
||||
|
||||
{
|
||||
typeof((IPAddress Address, int Subnet)).FullName, a =>
|
||||
{
|
||||
var inet = ((IPAddress Address, int Subnet))a;
|
||||
if (inet.Address == null) return (IPAddress.Any, inet.Subnet);
|
||||
return inet;
|
||||
}
|
||||
},
|
||||
{
|
||||
typeof((IPAddress Address, int Subnet)[]).FullName,
|
||||
a => getParamterArrayValue(typeof((IPAddress Address, int Subnet)), a, (IPAddress.Any, 0))
|
||||
},
|
||||
{
|
||||
typeof((IPAddress Address, int Subnet)?[]).FullName,
|
||||
a => getParamterArrayValue(typeof((IPAddress Address, int Subnet)?), a, null)
|
||||
},
|
||||
};
|
||||
|
||||
static object getParamterValue(Type type, object value, int level = 0)
|
||||
{
|
||||
if (type.FullName == "System.Byte[]") return value;
|
||||
if (type.FullName == "System.Char[]") return value;
|
||||
if (type.IsArray && level == 0)
|
||||
{
|
||||
var elementType = type.GetElementType();
|
||||
Type enumType = null;
|
||||
if (elementType.IsEnum) enumType = elementType;
|
||||
else if (elementType.IsNullableType() && elementType.GenericTypeArguments.First().IsEnum)
|
||||
enumType = elementType.GenericTypeArguments.First();
|
||||
if (enumType != null)
|
||||
return enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any()
|
||||
? getParamterArrayValue(typeof(long), value,
|
||||
elementType.IsEnum ? null : enumType.CreateInstanceGetDefaultValue())
|
||||
: getParamterArrayValue(typeof(int), value,
|
||||
elementType.IsEnum ? null : enumType.CreateInstanceGetDefaultValue());
|
||||
return dicGetParamterValue.TryGetValue(type.FullName, out var trydicarr) ? trydicarr(value) : value;
|
||||
}
|
||||
|
||||
if (type.IsNullableType()) type = type.GenericTypeArguments.First();
|
||||
if (type.IsEnum) return (int)value;
|
||||
if (dicGetParamterValue.TryGetValue(type.FullName, out var trydic)) return trydic(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public override DbParameter AppendParamter(List<DbParameter> _params, string parameterName, ColumnInfo col,
|
||||
Type type, object value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}";
|
||||
if (value != null) value = getParamterValue(type, value);
|
||||
var ret = new NpgsqlParameter { ParameterName = QuoteParamterName(parameterName), Value = value };
|
||||
|
||||
if (value != null && (value.GetType().IsEnum ||
|
||||
value.GetType().GenericTypeArguments.FirstOrDefault()?.IsEnum == true))
|
||||
{
|
||||
ret.DataTypeName = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
|
||||
if (tp != null)
|
||||
{
|
||||
var ntp = (NpgsqlDbType)tp;
|
||||
switch (ntp)
|
||||
{
|
||||
case NpgsqlDbType.Boolean:
|
||||
ret.NpgsqlDbType = NpgsqlDbType.Text;
|
||||
ret.DbType = DbType.String;
|
||||
ret.Value = string.Concat(value);
|
||||
break;
|
||||
case NpgsqlDbType.Numeric:
|
||||
ret.NpgsqlDbType = NpgsqlDbType.Double;
|
||||
ret.DbType = DbType.Double;
|
||||
ret.Value = Convert.ToDouble(FormatSql("{0}", value));
|
||||
break;
|
||||
default:
|
||||
ret.NpgsqlDbType = (NpgsqlDbType)tp.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (col != null)
|
||||
{
|
||||
var dbtype = (NpgsqlDbType)_orm.DbFirst.GetDbType(new DatabaseModel.DbColumnInfo
|
||||
{ DbTypeText = col.DbTypeText });
|
||||
if (dbtype != NpgsqlDbType.Unknown)
|
||||
{
|
||||
ret.NpgsqlDbType = dbtype;
|
||||
//if (col.DbSize != 0) ret.Size = col.DbSize;
|
||||
if (col.DbPrecision != 0)
|
||||
ret.Precision = col.DbPrecision;
|
||||
if (col.DbScale != 0)
|
||||
ret.Scale = col.DbScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_params?.Add(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override DbParameter[] GetDbParamtersByObject(string sql, object obj) =>
|
||||
Utils.GetDbParamtersByObject<NpgsqlParameter>(sql, obj, "@", (name, type, value) =>
|
||||
{
|
||||
if (value != null) value = getParamterValue(type, value);
|
||||
var ret = new NpgsqlParameter { ParameterName = $"@{name}", Value = value };
|
||||
//if (value.GetType().IsEnum || value.GetType().GenericTypeArguments.FirstOrDefault()?.IsEnum == true) {
|
||||
// ret.DataTypeName = "";
|
||||
//} else {
|
||||
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
|
||||
if (tp != null) ret.NpgsqlDbType = (NpgsqlDbType)tp.Value;
|
||||
//}
|
||||
return ret;
|
||||
});
|
||||
|
||||
public override string FormatSql(string sql, params object[] args) => sql?.FormatQuestDb(args);
|
||||
|
||||
public override string QuoteSqlNameAdapter(params string[] name)
|
||||
{
|
||||
if (name.Length == 1)
|
||||
{
|
||||
var nametrim = name[0].Trim();
|
||||
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
|
||||
return nametrim; //原生SQL
|
||||
if (nametrim.StartsWith("\"") && nametrim.EndsWith("\""))
|
||||
return nametrim;
|
||||
return $"\"{nametrim.Replace(".", "\".\"")}\"";
|
||||
}
|
||||
|
||||
return $"\"{string.Join("\".\"", name)}\"";
|
||||
}
|
||||
|
||||
public override string TrimQuoteSqlName(string name)
|
||||
{
|
||||
var nametrim = name.Trim();
|
||||
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
|
||||
return nametrim; //原生SQL
|
||||
return $"{nametrim.Trim('"').Replace("\".\"", ".").Replace(".\"", ".")}";
|
||||
}
|
||||
|
||||
public override string[] SplitTableName(string name) => GetSplitTableNames(name, '"', '"', 2);
|
||||
public override string QuoteParamterName(string name) => $"@{name}";
|
||||
public override string IsNull(string sql, object value) => $"coalesce({sql}, {value})";
|
||||
public override string StringConcat(string[] objs, Type[] types) => $"{string.Join(" || ", objs)}";
|
||||
public override string Mod(string left, string right, Type leftType, Type rightType) => $"{left} % {right}";
|
||||
public override string Div(string left, string right, Type leftType, Type rightType) => $"{left} / {right}";
|
||||
public override string Now => now_to_timezone;
|
||||
public override string NowUtc => "systimestamp()";
|
||||
|
||||
public override string QuoteWriteParamterAdapter(Type type, string paramterName) => paramterName;
|
||||
protected override string QuoteReadColumnAdapter(Type type, Type mapType, string columnName) => columnName;
|
||||
public override string GetNoneParamaterSqlValue(List<DbParameter> specialParams, string specialParamFlag,
|
||||
ColumnInfo col, Type type, object value)
|
||||
{
|
||||
if (value == null) return "NULL";
|
||||
if (type.IsNumberType()) return string.Format(CultureInfo.InvariantCulture, "{0}", value);
|
||||
|
||||
value = getParamterValue(type, value);
|
||||
var type2 = value.GetType();
|
||||
if (type2 == typeof(byte[])) return $"'\\x{CommonUtils.BytesSqlRaw(value as byte[])}'";
|
||||
else if (dicGetParamterValue.ContainsKey(type2.FullName))
|
||||
{
|
||||
value = string.Concat(value);
|
||||
}
|
||||
|
||||
return FormatSql("{0}", value, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace FreeSql
|
||||
{
|
||||
public enum SampleUnit
|
||||
{
|
||||
microsecond = 'U',
|
||||
millisecond = 'T',
|
||||
second = 's',
|
||||
minute = 'm',
|
||||
hour = 'h',
|
||||
day = 'd',
|
||||
month = 'M',
|
||||
year = 'y',
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace FreeSql.Provider.QuestDb.Subtable
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property, Inherited = true)]
|
||||
public class AutoSubtableAttribute : Attribute
|
||||
{
|
||||
public SubtableType? SubtableType
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public AutoSubtableAttribute(SubtableType type)
|
||||
{
|
||||
SubtableType = type;
|
||||
}
|
||||
}
|
||||
}
|
19
Providers/FreeSql.Provider.QuestDb/Subtable/SubtableType.cs
Normal file
19
Providers/FreeSql.Provider.QuestDb/Subtable/SubtableType.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace FreeSql.Provider.QuestDb.Subtable
|
||||
{
|
||||
public enum SubtableType
|
||||
{
|
||||
Year = 1,
|
||||
Month = 2,
|
||||
Day = 3,
|
||||
Hour = 4,
|
||||
Second = 5,
|
||||
Minute = 6,
|
||||
Millisecond = 7,
|
||||
Weekday = 8,
|
||||
Quarter = 9
|
||||
}
|
||||
}
|
BIN
Providers/FreeSql.Provider.QuestDb/key.snk
Normal file
BIN
Providers/FreeSql.Provider.QuestDb/key.snk
Normal file
Binary file not shown.
Reference in New Issue
Block a user