Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit ab9d727

Browse files
committed
2 parents a7365ad + 86dfdfe commit ab9d727

25 files changed

+575
-72
lines changed

src/ServiceStack.OrmLite.Firebird/FirebirdOrmLiteDialectProvider.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,8 @@ public override void DropColumn(IDbConnection db, Type modelType, string columnN
801801

802802
db.ExecuteSql(command);
803803
}
804+
805+
public override string SqlConcat(IEnumerable<object> args) => string.Join(" || ", args);
804806
}
805807
}
806808

src/ServiceStack.OrmLite.Firebird/FirebirdSqlExpression.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,6 @@ protected override object VisitColumnAccessMethod(MethodCallExpression m)
3030
}
3131
return new PartialSqlString(statement);
3232
}
33-
34-
protected override PartialSqlString ToConcatPartialString(List<object> args)
35-
{
36-
return new PartialSqlString(string.Join(" || ", args));
37-
}
3833
}
3934
}
4035

src/ServiceStack.OrmLite.MySql/MySqlDialectProvider.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ public MySqlDialectProvider()
5353

5454
public static string RowVersionTriggerFormat = "{0}RowVersionUpdateTrigger";
5555

56+
public override string GetLoadChildrenSubSelect<From>(SqlExpression<From> expr)
57+
{
58+
return $"SELECT * FROM ({base.GetLoadChildrenSubSelect(expr)}) AS COUNT";
59+
}
5660
public override string ToPostDropTableStatement(ModelDefinition modelDef)
5761
{
5862
if (modelDef.RowVersion != null)
@@ -208,6 +212,9 @@ public string GetColumnDefinition(FieldDefinition fieldDef)
208212
return ret;
209213
}
210214

215+
public override string SqlCurrency(string fieldOrValue, string currencySymbol) =>
216+
SqlConcat(new []{ "'" + currencySymbol + "'", "cast(" + fieldOrValue + " as decimal(15,2))" });
217+
211218
protected MySqlConnection Unwrap(IDbConnection db)
212219
{
213220
return (MySqlConnection)db.ToDbConnection();

src/ServiceStack.OrmLite.MySql/MySqlExpression.cs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
1-
using System.Collections.Generic;
2-
using System.Linq.Expressions;
3-
4-
namespace ServiceStack.OrmLite.MySql
1+
namespace ServiceStack.OrmLite.MySql
52
{
63
public class MySqlExpression<T> : SqlExpression<T>
74
{
85
public MySqlExpression(IOrmLiteDialectProvider dialectProvider)
96
: base(dialectProvider) {}
107

11-
protected override PartialSqlString ToConcatPartialString(List<object> args)
12-
{
13-
return new PartialSqlString($"CONCAT({string.Join(", ", args)})");
14-
}
15-
168
protected override string ToCast(string quotedColName)
179
{
1810
return $"cast({quotedColName} as char(1000))";

src/ServiceStack.OrmLite.Oracle/OracleOrmLiteDialectProvider.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,5 +1084,7 @@ public override string ToRowCountStatement(string innerSql)
10841084
{
10851085
return "SELECT COUNT(*) FROM ({0})".Fmt(innerSql);
10861086
}
1087+
1088+
public override string SqlConcat(IEnumerable<object> args) => string.Join(" || ", args);
10871089
}
10881090
}

src/ServiceStack.OrmLite.Oracle/OracleSqlExpression.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,6 @@ public override SqlExpression<T> OrderByRandom()
5252
{
5353
return base.OrderBy("dbms_random.value");
5454
}
55-
56-
protected override PartialSqlString ToConcatPartialString(List<object> args)
57-
{
58-
return new PartialSqlString(string.Join(" || ", args));
59-
}
6055
}
6156
}
6257

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using NUnit.Framework;
7+
using ServiceStack.OrmLite.Tests;
8+
using ServiceStack.OrmLite.Tests.UseCase;
9+
using ServiceStack.Text;
10+
using Customer = ServiceStack.OrmLite.Tests.Customer;
11+
using Order = ServiceStack.OrmLite.Tests.Order;
12+
13+
namespace ServiceStack.OrmLite.PostgreSQL.Tests
14+
{
15+
class NormalizeTests
16+
: OrmLiteTestBase
17+
{
18+
public NormalizeTests() : base(Dialect.PostgreSql) { }
19+
20+
[Test]
21+
public void Can_create_and_populate_tables_without_quotes()
22+
{
23+
using (var db = OpenDbConnection())
24+
{
25+
PostgreSqlDialectProvider.Instance.Normalize = true;
26+
27+
CustomerOrdersUseCase.DropTables(db); //Has conflicting 'Order' table
28+
db.DropTable<Order>();
29+
db.DropTable<CustomerAddress>();
30+
db.DropTable<Customer>();
31+
32+
db.CreateTable<Customer>();
33+
db.CreateTable<CustomerAddress>();
34+
db.CreateTable<Order>();
35+
36+
db.GetLastSql().Print();
37+
38+
var customer = new Customer
39+
{
40+
Name = "Customer 1",
41+
PrimaryAddress = new CustomerAddress
42+
{
43+
AddressLine1 = "1 Humpty Street",
44+
City = "Humpty Doo",
45+
State = "Northern Territory",
46+
Country = "Australia"
47+
},
48+
Orders = new[] {
49+
new Order { LineItem = "Line 1", Qty = 1, Cost = 1.99m },
50+
new Order { LineItem = "Line 2", Qty = 2, Cost = 2.99m },
51+
}.ToList(),
52+
};
53+
54+
db.Save(customer, references: true);
55+
db.GetLastSql().Print();
56+
57+
var dbCustomer = db.SingleById<Customer>(customer.Id);
58+
Assert.That(dbCustomer.Name, Is.EqualTo(customer.Name));
59+
dbCustomer = db.SqlList<Customer>("select * from Customer where Id = @Id", new { customer.Id })[0];
60+
Assert.That(dbCustomer.Name, Is.EqualTo(customer.Name));
61+
62+
var address = db.Single<CustomerAddress>(x => x.CustomerId == customer.Id && x.Id == customer.PrimaryAddress.Id);
63+
Assert.That(address.Country, Is.EqualTo("Australia"));
64+
65+
var orders = db.Select<Order>(x => x.CustomerId == customer.Id);
66+
var totalQty = orders.Sum(x => x.Qty);
67+
Assert.That(totalQty, Is.EqualTo(3));
68+
69+
PostgreSqlDialectProvider.Instance.Normalize = false;
70+
}
71+
}
72+
}
73+
}

src/ServiceStack.OrmLite.PostgreSQL/PostgreSQLDialectProvider.cs

Lines changed: 151 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,106 @@ public PostgreSqlDialectProvider()
6262
};
6363
}
6464

65+
private bool normalize;
66+
public bool Normalize
67+
{
68+
get => normalize;
69+
set
70+
{
71+
normalize = value;
72+
NamingStrategy = normalize
73+
? new OrmLiteNamingStrategyBase()
74+
: new PostgreSqlNamingStrategy();
75+
}
76+
}
77+
78+
//https://www.postgresql.org/docs/7.3/static/sql-keywords-appendix.html
79+
public static HashSet<string> ReservedWords = new HashSet<string>(new[]
80+
{
81+
"ALL",
82+
"ANALYSE",
83+
"ANALYZE",
84+
"AND",
85+
"ANY",
86+
"AS",
87+
"ASC",
88+
"AUTHORIZATION",
89+
"BETWEEN",
90+
"BINARY",
91+
"BOTH",
92+
"CASE",
93+
"CAST",
94+
"CHECK",
95+
"COLLATE",
96+
"COLUMN",
97+
"CONSTRAINT",
98+
"CURRENT_DATE",
99+
"CURRENT_TIME",
100+
"CURRENT_TIMESTAMP",
101+
"CURRENT_USER",
102+
"DEFAULT",
103+
"DEFERRABLE",
104+
"DISTINCT",
105+
"DO",
106+
"ELSE",
107+
"END",
108+
"EXCEPT",
109+
"FOR",
110+
"FOREIGN",
111+
"FREEZE",
112+
"FROM",
113+
"FULL",
114+
"HAVING",
115+
"ILIKE",
116+
"IN",
117+
"INITIALLY",
118+
"INNER",
119+
"INTERSECT",
120+
"INTO",
121+
"IS",
122+
"ISNULL",
123+
"JOIN",
124+
"LEADING",
125+
"LEFT",
126+
"LIKE",
127+
"LIMIT",
128+
"LOCALTIME",
129+
"LOCALTIMESTAMP",
130+
"NEW",
131+
"NOT",
132+
"NOTNULL",
133+
"NULL",
134+
"OFF",
135+
"OFFSET",
136+
"OLD",
137+
"ON",
138+
"ONLY",
139+
"OR",
140+
"ORDER",
141+
"OUTER",
142+
"OVERLAPS",
143+
"PLACING",
144+
"PRIMARY",
145+
"REFERENCES",
146+
"RIGHT",
147+
"SELECT",
148+
"SESSION_USER",
149+
"SIMILAR",
150+
"SOME",
151+
"TABLE",
152+
"THEN",
153+
"TO",
154+
"TRAILING",
155+
"TRUE",
156+
"UNION",
157+
"UNIQUE",
158+
"USER",
159+
"USING",
160+
"VERBOSE",
161+
"WHEN",
162+
"WHERE",
163+
}, StringComparer.OrdinalIgnoreCase);
164+
65165
public override string GetColumnDefinition(FieldDefinition fieldDef)
66166
{
67167
if (fieldDef.IsRowVersion)
@@ -160,8 +260,9 @@ public override IDbDataParameter CreateParam()
160260

161261
public override bool DoesTableExist(IDbCommand dbCmd, string tableName, string schema = null)
162262
{
163-
var sql = "SELECT COUNT(*) FROM pg_class WHERE relname = {0}"
164-
.SqlFmt(tableName);
263+
var sql = !Normalize || ReservedWords.Contains(tableName)
264+
? "SELECT COUNT(*) FROM pg_class WHERE relname = {0}".SqlFmt(tableName)
265+
: "SELECT COUNT(*) FROM pg_class WHERE lower(relname) = {0}".SqlFmt(tableName.ToLower());
165266

166267
var conn = dbCmd.Connection;
167268
if (conn != null)
@@ -172,8 +273,11 @@ public override bool DoesTableExist(IDbCommand dbCmd, string tableName, string s
172273

173274
// If a search path (schema) is specified, and there is only one, then assume the CREATE TABLE directive should apply to that schema.
174275
if (!string.IsNullOrEmpty(schema) && !schema.Contains(","))
175-
sql = "SELECT COUNT(*) FROM pg_class JOIN pg_catalog.pg_namespace n ON n.oid = pg_class.relnamespace WHERE relname = {0} AND nspname = {1}"
176-
.SqlFmt(tableName, schema);
276+
{
277+
sql = !Normalize || ReservedWords.Contains(schema)
278+
? "SELECT COUNT(*) FROM pg_class JOIN pg_catalog.pg_namespace n ON n.oid = pg_class.relnamespace WHERE relname = {0} AND nspname = {1}".SqlFmt(tableName, schema)
279+
: "SELECT COUNT(*) FROM pg_class JOIN pg_catalog.pg_namespace n ON n.oid = pg_class.relnamespace WHERE lower(relname) = {0} AND lower(nspname) = {1}".SqlFmt(tableName.ToLower(), schema.ToLower());
280+
}
177281
}
178282

179283
var result = dbCmd.ExecLongScalar(sql);
@@ -183,11 +287,23 @@ public override bool DoesTableExist(IDbCommand dbCmd, string tableName, string s
183287

184288
public override bool DoesColumnExist(IDbConnection db, string columnName, string tableName, string schema = null)
185289
{
186-
var sql = "SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @tableName AND COLUMN_NAME = @columnName"
187-
.SqlFmt(tableName, columnName);
290+
var sql = !Normalize || ReservedWords.Contains(tableName)
291+
? "SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @tableName".SqlFmt(tableName)
292+
: "SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE lower(TABLE_NAME) = @tableName".SqlFmt(tableName.ToLower());
293+
294+
sql += !Normalize || ReservedWords.Contains(columnName)
295+
? " AND COLUMN_NAME = @columnName".SqlFmt(columnName)
296+
: " AND lower(COLUMN_NAME) = @columnName".SqlFmt(columnName.ToLower());
188297

189298
if (schema != null)
190-
sql += " AND TABLE_SCHEMA = @schema";
299+
{
300+
sql += !Normalize || ReservedWords.Contains(schema)
301+
? " AND TABLE_SCHEMA = @schema"
302+
: " AND lower(TABLE_SCHEMA) = @schema";
303+
304+
if (Normalize)
305+
schema = schema.ToLower();
306+
}
191307

192308
var result = db.SqlScalar<long>(sql, new { tableName, columnName, schema });
193309

@@ -217,14 +333,31 @@ public override string ToExecuteProcedureStatement(object objWithProperties)
217333
return sql;
218334
}
219335

336+
public override string GetQuotedTableName(string tableName, string schema = null)
337+
{
338+
return !Normalize || ReservedWords.Contains(tableName) || (schema != null && ReservedWords.Contains(schema))
339+
? base.GetQuotedTableName(tableName, schema)
340+
: schema != null
341+
? schema + "." + tableName
342+
: tableName;
343+
}
344+
345+
public override string GetQuotedName(string name)
346+
{
347+
return !Normalize || ReservedWords.Contains(name)
348+
? base.GetQuotedName(name)
349+
: name;
350+
}
351+
220352
public override string GetQuotedTableName(ModelDefinition modelDef)
221353
{
222354
if (!modelDef.IsInSchema)
223-
{
224355
return base.GetQuotedTableName(modelDef);
225-
}
356+
if (Normalize && !ReservedWords.Contains(modelDef.ModelName) && !ReservedWords.Contains(modelDef.Schema))
357+
return modelDef.Schema + "." + base.NamingStrategy.GetTableName(modelDef.ModelName);
358+
226359
string escapedSchema = modelDef.Schema.Replace(".", "\".\"");
227-
return string.Format("\"{0}\".\"{1}\"", escapedSchema, base.NamingStrategy.GetTableName(modelDef.ModelName));
360+
return $"\"{escapedSchema}\".\"{base.NamingStrategy.GetTableName(modelDef.ModelName)}\"";
228361
}
229362

230363
public override string GetLastInsertIdSqlSuffix<T>()
@@ -236,7 +369,9 @@ public override string GetLastInsertIdSqlSuffix<T>()
236369
{
237370
var modelDef = GetModel(typeof(T));
238371
var pkName = NamingStrategy.GetColumnName(modelDef.PrimaryKey.FieldName);
239-
return $" RETURNING \"{pkName}\"";
372+
return !Normalize
373+
? $" RETURNING \"{pkName}\""
374+
: " RETURNING " + pkName;
240375
}
241376

242377
return "; " + SelectIdentitySql;
@@ -313,6 +448,11 @@ public override void PrepareStoredProcedureStatement<T>(IDbCommand cmd, T obj)
313448
SetParameterValues<T>(cmd, obj);
314449
}
315450

451+
public override string SqlConcat(IEnumerable<object> args) => string.Join(" || ", args);
452+
453+
public override string SqlCurrency(string fieldOrValue, string currencySymbol) => currencySymbol == "$"
454+
? fieldOrValue + "::text::money::text"
455+
: "replace(" + fieldOrValue + "::text::money::text,'$','" + currencySymbol + "')";
316456

317457
protected NpgsqlConnection Unwrap(IDbConnection db)
318458
{

src/ServiceStack.OrmLite.PostgreSQL/PostgreSqlExpression.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using System.Collections.Generic;
21
using System.Linq;
32

43
namespace ServiceStack.OrmLite.PostgreSQL
@@ -25,11 +24,6 @@ public override SqlExpression<T> OrderByRandom()
2524
{
2625
return base.OrderBy("RANDOM()");
2726
}
28-
29-
protected override PartialSqlString ToConcatPartialString(List<object> args)
30-
{
31-
return new PartialSqlString(string.Join(" || ", args));
32-
}
3327
}
3428

3529
}

0 commit comments

Comments
 (0)