@an5/adapters 0.2.5 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +283 -305
- package/dist/an5Adapter.d.ts +142 -7
- package/dist/an5Adapter.js +998 -68
- package/dist/base/metadata.d.ts +10 -0
- package/dist/base/metadata.js +107 -0
- package/dist/base/sql.d.ts +19 -1
- package/dist/base/sql.js +152 -24
- package/dist/base/types.d.ts +10 -1
- package/dist/browser.d.ts +4 -1
- package/dist/browser.js +9 -2
- package/dist/googlesheets/adapter.d.ts +1 -0
- package/dist/googlesheets/adapter.js +9 -2
- package/dist/googlesheets/config.d.ts +4 -4
- package/dist/googlesheets/helpers.js +2 -0
- package/dist/googlesheets/parseConnectionString.js +5 -2
- package/dist/googlesheets/sqlExecutor.js +29 -24
- package/dist/googlesheets/tableClient.js +14 -5
- package/dist/index.d.ts +5 -1
- package/dist/index.js +15 -1
- package/dist/mssql/engine.js +8 -4
- package/dist/mysql/engine.js +1 -1
- package/dist/nbase/client.d.ts +92 -0
- package/dist/nbase/client.js +147 -0
- package/dist/nbase/index.d.ts +47 -0
- package/dist/nbase/index.js +80 -0
- package/dist/postgres/engine.js +1 -1
- package/dist/sqlite/browserEngine.d.ts +27 -0
- package/dist/sqlite/browserEngine.js +161 -0
- package/dist/sqlite/engine.js +15 -3
- package/dist/sqlite/index.d.ts +1 -0
- package/dist/sqlite/index.js +1 -0
- package/dist/typed.d.ts +5 -0
- package/dist/typed.js +2 -0
- package/dotnet/An5Adapter.cs +1112 -275
- package/dotnet/Base/Core.cs +380 -82
- package/dotnet/Mssql/MssqlEngine.cs +145 -144
- package/dotnet/Postgres/PostgresEngine.cs +149 -121
- package/dotnet/Sqlite/SqliteEngine.cs +214 -0
- package/golang/an5_adapter.go +314 -0
- package/golang/base/base.go +100 -0
- package/golang/base/metadata.go +116 -0
- package/golang/base/where.go +311 -0
- package/golang/go.mod +3 -0
- package/golang/mssql/mssql.go +32 -0
- package/golang/postgres/postgres.go +37 -0
- package/golang/sqlite/sqlite.go +14 -0
- package/golang/sqlite_test.go +42 -0
- package/golang/table_client.go +1329 -0
- package/package.json +26 -9
- package/python/an5_adapter.py +184 -97
- package/python/base/__init__.py +3 -3
- package/python/base/dialects.py +11 -8
- package/python/base/metadata.py +59 -10
- package/python/base/sql.py +202 -121
- package/python/mssql/__init__.py +1 -1
- package/python/mssql/provider.py +62 -62
- package/python/postgres/__init__.py +1 -1
- package/python/postgres/provider.py +15 -15
- package/python/sqlite/__init__.py +3 -0
- package/python/sqlite/provider.py +83 -0
- package/python/table_client.py +636 -216
- package/rust/Cargo.toml +31 -0
- package/rust/README.md +71 -0
- package/rust/src/adapter.rs +1312 -0
- package/rust/src/base/dialect.rs +172 -0
- package/rust/src/base/metadata.rs +134 -0
- package/rust/src/base/mod.rs +17 -0
- package/rust/src/base/where_builder.rs +405 -0
- package/rust/src/lib.rs +75 -0
- package/typescript/src/an5Adapter.ts +1515 -505
- package/typescript/src/base/index.ts +3 -3
- package/typescript/src/base/metadata.ts +148 -28
- package/typescript/src/base/sql.ts +264 -98
- package/typescript/src/base/types.ts +33 -24
- package/typescript/src/browser.ts +10 -6
- package/typescript/src/config.ts +95 -95
- package/typescript/src/googlesheets/adapter.ts +269 -259
- package/typescript/src/googlesheets/an5SheetsAdapter.ts +3 -3
- package/typescript/src/googlesheets/config.ts +47 -47
- package/typescript/src/googlesheets/helpers.ts +144 -143
- package/typescript/src/googlesheets/index.ts +3 -3
- package/typescript/src/googlesheets/parseConnectionString.ts +48 -46
- package/typescript/src/googlesheets/retry.ts +126 -126
- package/typescript/src/googlesheets/sqlExecutor.ts +304 -301
- package/typescript/src/googlesheets/tableClient.ts +461 -455
- package/typescript/src/googlesheets/types.ts +6 -6
- package/typescript/src/index.ts +48 -27
- package/typescript/src/mssql/engine.ts +134 -132
- package/typescript/src/mssql/index.ts +1 -1
- package/typescript/src/mysql/engine.ts +80 -80
- package/typescript/src/mysql/index.ts +1 -1
- package/typescript/src/nbase/client.ts +214 -0
- package/typescript/src/nbase/index.ts +104 -0
- package/typescript/src/postgres/engine.ts +87 -87
- package/typescript/src/postgres/index.ts +1 -1
- package/typescript/src/sqlite/browserEngine.ts +192 -0
- package/typescript/src/sqlite/engine.ts +66 -55
- package/typescript/src/sqlite/index.ts +3 -1
- package/typescript/src/typed.ts +52 -0
|
@@ -1,144 +1,145 @@
|
|
|
1
|
-
using System;
|
|
2
|
-
using System.Collections.Generic;
|
|
3
|
-
using System.Data;
|
|
4
|
-
using System.Reflection;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
private readonly
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
[ThreadStatic] private static
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
isInTransaction =
|
|
29
|
-
|
|
30
|
-
conn
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
var
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
using var
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
var
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
using var
|
|
80
|
-
var
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
conn
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
private readonly
|
|
131
|
-
private readonly
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
public override void
|
|
142
|
-
public override void
|
|
143
|
-
|
|
144
|
-
}
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using System.Data;
|
|
4
|
+
using System.Reflection;
|
|
5
|
+
using Microsoft.Data.SqlClient;
|
|
6
|
+
|
|
7
|
+
namespace An5Orm
|
|
8
|
+
{
|
|
9
|
+
// ─── MSSQL Engine ──────────────────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
internal class MssqlEngine : IQueryEngine
|
|
12
|
+
{
|
|
13
|
+
public Dialect Dialect => Dialect.Mssql;
|
|
14
|
+
private readonly string _connectionString;
|
|
15
|
+
private readonly int _commandTimeout;
|
|
16
|
+
|
|
17
|
+
[ThreadStatic] private static SqlConnection _txConn;
|
|
18
|
+
[ThreadStatic] private static SqlTransaction _tx;
|
|
19
|
+
|
|
20
|
+
public MssqlEngine(string connectionString, int commandTimeout)
|
|
21
|
+
{
|
|
22
|
+
_connectionString = connectionString;
|
|
23
|
+
_commandTimeout = commandTimeout;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private SqlConnection OpenConnection(out bool isInTransaction)
|
|
27
|
+
{
|
|
28
|
+
if (_txConn != null) { isInTransaction = true; return _txConn; }
|
|
29
|
+
isInTransaction = false;
|
|
30
|
+
var conn = new SqlConnection(_connectionString);
|
|
31
|
+
conn.Open();
|
|
32
|
+
return conn;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private SqlCommand BuildCommand(
|
|
36
|
+
SqlConnection conn, string sql, Dictionary<string, object> parameters)
|
|
37
|
+
{
|
|
38
|
+
var cmd = new SqlCommand(sql, conn) { CommandTimeout = _commandTimeout };
|
|
39
|
+
if (_tx != null) cmd.Transaction = _tx;
|
|
40
|
+
if (parameters != null)
|
|
41
|
+
{
|
|
42
|
+
foreach (var kv in parameters)
|
|
43
|
+
{
|
|
44
|
+
var paramName = kv.Key.StartsWith("@") ? kv.Key : "@" + kv.Key;
|
|
45
|
+
cmd.Parameters.AddWithValue(paramName, kv.Value ?? DBNull.Value);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return cmd;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public List<Dictionary<string, object>> QueryRaw(string sql, Dictionary<string, object> parameters)
|
|
52
|
+
{
|
|
53
|
+
var results = new List<Dictionary<string, object>>();
|
|
54
|
+
var conn = OpenConnection(out bool isTx);
|
|
55
|
+
try
|
|
56
|
+
{
|
|
57
|
+
using var cmd = BuildCommand(conn, sql, parameters);
|
|
58
|
+
using var reader = cmd.ExecuteReader();
|
|
59
|
+
while (reader.Read())
|
|
60
|
+
{
|
|
61
|
+
var row = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
|
|
62
|
+
for (int i = 0; i < reader.FieldCount; i++)
|
|
63
|
+
{
|
|
64
|
+
row[reader.GetName(i)] = reader.IsDBNull(i) ? null : reader.GetValue(i);
|
|
65
|
+
}
|
|
66
|
+
results.Add(row);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
finally { if (!isTx) conn.Dispose(); }
|
|
70
|
+
return results;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public List<T> QueryRaw<T>(string sql, Dictionary<string, object> parameters) where T : new()
|
|
74
|
+
{
|
|
75
|
+
var results = new List<T>();
|
|
76
|
+
var conn = OpenConnection(out bool isTx);
|
|
77
|
+
try
|
|
78
|
+
{
|
|
79
|
+
using var cmd = BuildCommand(conn, sql, parameters);
|
|
80
|
+
using var reader = cmd.ExecuteReader();
|
|
81
|
+
var props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
|
82
|
+
while (reader.Read())
|
|
83
|
+
{
|
|
84
|
+
var item = new T();
|
|
85
|
+
foreach (var prop in props)
|
|
86
|
+
{
|
|
87
|
+
if (!HasColumn(reader, prop.Name)) continue;
|
|
88
|
+
var val = reader[prop.Name];
|
|
89
|
+
if (val == DBNull.Value) continue;
|
|
90
|
+
try { prop.SetValue(item, Convert.ChangeType(val, prop.PropertyType)); } catch { }
|
|
91
|
+
}
|
|
92
|
+
results.Add(item);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
finally { if (!isTx) conn.Dispose(); }
|
|
96
|
+
return results;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public int ExecuteRaw(string sql, Dictionary<string, object> parameters)
|
|
100
|
+
{
|
|
101
|
+
var conn = OpenConnection(out bool isTx);
|
|
102
|
+
try
|
|
103
|
+
{
|
|
104
|
+
using var cmd = BuildCommand(conn, sql, parameters);
|
|
105
|
+
return cmd.ExecuteNonQuery();
|
|
106
|
+
}
|
|
107
|
+
finally { if (!isTx) conn.Dispose(); }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private static bool HasColumn(SqlDataReader reader, string name)
|
|
111
|
+
{
|
|
112
|
+
for (int i = 0; i < reader.FieldCount; i++)
|
|
113
|
+
if (reader.GetName(i).Equals(name, StringComparison.OrdinalIgnoreCase)) return true;
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
public An5TransactionBase BeginTransaction()
|
|
118
|
+
{
|
|
119
|
+
var conn = new SqlConnection(_connectionString);
|
|
120
|
+
conn.Open();
|
|
121
|
+
var tx = conn.BeginTransaction();
|
|
122
|
+
_txConn = conn;
|
|
123
|
+
_tx = tx;
|
|
124
|
+
return new MssqlTransaction(conn, tx, () => { _txConn = null; _tx = null; });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
internal class MssqlTransaction : An5TransactionBase
|
|
129
|
+
{
|
|
130
|
+
private readonly SqlConnection _conn;
|
|
131
|
+
private readonly SqlTransaction _tx;
|
|
132
|
+
private readonly Action _cleanup;
|
|
133
|
+
|
|
134
|
+
public MssqlTransaction(SqlConnection conn, SqlTransaction tx, Action cleanup)
|
|
135
|
+
{
|
|
136
|
+
_conn = conn;
|
|
137
|
+
_tx = tx;
|
|
138
|
+
_cleanup = cleanup;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
public override void Commit() { _tx.Commit(); _cleanup(); }
|
|
142
|
+
public override void Rollback() { _tx.Rollback(); _cleanup(); }
|
|
143
|
+
public override void Dispose() { _tx.Dispose(); _conn.Dispose(); _cleanup(); }
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -1,121 +1,149 @@
|
|
|
1
|
-
using System;
|
|
2
|
-
using System.Collections.Generic;
|
|
3
|
-
using System.Data;
|
|
4
|
-
using System.Reflection;
|
|
5
|
-
|
|
6
|
-
namespace An5Orm
|
|
7
|
-
{
|
|
8
|
-
// ─── PostgreSQL Engine ─────────────────────────────────────────────────────
|
|
9
|
-
|
|
10
|
-
internal class PostgresEngine : IQueryEngine
|
|
11
|
-
{
|
|
12
|
-
public Dialect Dialect => Dialect.Postgres;
|
|
13
|
-
private readonly string _connectionString;
|
|
14
|
-
private readonly int _commandTimeout;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
{
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
var
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
public
|
|
120
|
-
|
|
121
|
-
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using System.Data;
|
|
4
|
+
using System.Reflection;
|
|
5
|
+
|
|
6
|
+
namespace An5Orm
|
|
7
|
+
{
|
|
8
|
+
// ─── PostgreSQL Engine ─────────────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
internal class PostgresEngine : IQueryEngine
|
|
11
|
+
{
|
|
12
|
+
public Dialect Dialect => Dialect.Postgres;
|
|
13
|
+
private readonly string _connectionString;
|
|
14
|
+
private readonly int _commandTimeout;
|
|
15
|
+
|
|
16
|
+
// Same shape as MssqlEngine: while a transaction is open, statements
|
|
17
|
+
// have to run on its connection and carry its transaction, or they land
|
|
18
|
+
// outside it and commit/rollback do not cover them.
|
|
19
|
+
[ThreadStatic] private static Npgsql.NpgsqlConnection _txConn;
|
|
20
|
+
[ThreadStatic] private static Npgsql.NpgsqlTransaction _tx;
|
|
21
|
+
|
|
22
|
+
public PostgresEngine(string connectionString, int commandTimeout)
|
|
23
|
+
{
|
|
24
|
+
_connectionString = connectionString;
|
|
25
|
+
_commandTimeout = commandTimeout;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private Npgsql.NpgsqlConnection OpenConnection(out bool isInTransaction)
|
|
29
|
+
{
|
|
30
|
+
if (_txConn != null) { isInTransaction = true; return _txConn; }
|
|
31
|
+
isInTransaction = false;
|
|
32
|
+
var conn = new Npgsql.NpgsqlConnection(_connectionString);
|
|
33
|
+
conn.Open();
|
|
34
|
+
return conn;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private Npgsql.NpgsqlCommand BuildCommand(
|
|
38
|
+
Npgsql.NpgsqlConnection conn, string sql, Dictionary<string, object> parameters)
|
|
39
|
+
{
|
|
40
|
+
var cmd = new Npgsql.NpgsqlCommand(sql, conn) { CommandTimeout = _commandTimeout };
|
|
41
|
+
if (_tx != null) cmd.Transaction = _tx;
|
|
42
|
+
if (parameters != null)
|
|
43
|
+
{
|
|
44
|
+
foreach (var kv in parameters)
|
|
45
|
+
{
|
|
46
|
+
var paramName = kv.Key.StartsWith("@") ? kv.Key : "@" + kv.Key;
|
|
47
|
+
cmd.Parameters.AddWithValue(paramName, kv.Value ?? DBNull.Value);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return cmd;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public List<Dictionary<string, object>> QueryRaw(string sql, Dictionary<string, object> parameters)
|
|
54
|
+
{
|
|
55
|
+
var results = new List<Dictionary<string, object>>();
|
|
56
|
+
var conn = OpenConnection(out bool isTx);
|
|
57
|
+
try
|
|
58
|
+
{
|
|
59
|
+
using var cmd = BuildCommand(conn, sql, parameters);
|
|
60
|
+
using var reader = cmd.ExecuteReader();
|
|
61
|
+
while (reader.Read())
|
|
62
|
+
{
|
|
63
|
+
var row = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
|
|
64
|
+
for (int i = 0; i < reader.FieldCount; i++)
|
|
65
|
+
{
|
|
66
|
+
row[reader.GetName(i)] = reader.IsDBNull(i) ? null : reader.GetValue(i);
|
|
67
|
+
}
|
|
68
|
+
results.Add(row);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
finally { if (!isTx) conn.Dispose(); }
|
|
72
|
+
return results;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public List<T> QueryRaw<T>(string sql, Dictionary<string, object> parameters) where T : new()
|
|
76
|
+
{
|
|
77
|
+
var results = new List<T>();
|
|
78
|
+
var conn = OpenConnection(out bool isTx);
|
|
79
|
+
try
|
|
80
|
+
{
|
|
81
|
+
using var cmd = BuildCommand(conn, sql, parameters);
|
|
82
|
+
using var reader = cmd.ExecuteReader();
|
|
83
|
+
var props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
|
84
|
+
while (reader.Read())
|
|
85
|
+
{
|
|
86
|
+
var item = new T();
|
|
87
|
+
foreach (var prop in props)
|
|
88
|
+
{
|
|
89
|
+
if (!HasColumn(reader, prop.Name)) continue;
|
|
90
|
+
var val = reader[prop.Name];
|
|
91
|
+
if (val == DBNull.Value) continue;
|
|
92
|
+
try { prop.SetValue(item, Convert.ChangeType(val, prop.PropertyType)); } catch { }
|
|
93
|
+
}
|
|
94
|
+
results.Add(item);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
finally { if (!isTx) conn.Dispose(); }
|
|
98
|
+
return results;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public int ExecuteRaw(string sql, Dictionary<string, object> parameters)
|
|
102
|
+
{
|
|
103
|
+
var conn = OpenConnection(out bool isTx);
|
|
104
|
+
try
|
|
105
|
+
{
|
|
106
|
+
using var cmd = BuildCommand(conn, sql, parameters);
|
|
107
|
+
return cmd.ExecuteNonQuery();
|
|
108
|
+
}
|
|
109
|
+
finally { if (!isTx) conn.Dispose(); }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private static bool HasColumn(Npgsql.NpgsqlDataReader reader, string name)
|
|
113
|
+
{
|
|
114
|
+
for (int i = 0; i < reader.FieldCount; i++)
|
|
115
|
+
if (reader.GetName(i).Equals(name, StringComparison.OrdinalIgnoreCase)) return true;
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public An5TransactionBase BeginTransaction()
|
|
120
|
+
{
|
|
121
|
+
if (_txConn != null)
|
|
122
|
+
throw new InvalidOperationException("A transaction is already open on this thread.");
|
|
123
|
+
var conn = new Npgsql.NpgsqlConnection(_connectionString);
|
|
124
|
+
conn.Open();
|
|
125
|
+
var tx = conn.BeginTransaction();
|
|
126
|
+
_txConn = conn;
|
|
127
|
+
_tx = tx;
|
|
128
|
+
return new PostgresTransaction(conn, tx, () => { _txConn = null; _tx = null; });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
internal class PostgresTransaction : An5TransactionBase
|
|
133
|
+
{
|
|
134
|
+
private readonly Npgsql.NpgsqlConnection _conn;
|
|
135
|
+
private readonly Npgsql.NpgsqlTransaction _tx;
|
|
136
|
+
private readonly Action _cleanup;
|
|
137
|
+
|
|
138
|
+
public PostgresTransaction(Npgsql.NpgsqlConnection conn, Npgsql.NpgsqlTransaction tx, Action cleanup)
|
|
139
|
+
{
|
|
140
|
+
_conn = conn;
|
|
141
|
+
_tx = tx;
|
|
142
|
+
_cleanup = cleanup;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public override void Commit() { _tx.Commit(); _cleanup(); }
|
|
146
|
+
public override void Rollback() { _tx.Rollback(); _cleanup(); }
|
|
147
|
+
public override void Dispose() { _tx.Dispose(); _conn.Dispose(); _cleanup(); }
|
|
148
|
+
}
|
|
149
|
+
}
|