From 463368b31df97b322b3f59d02ce875ea09aa5baa Mon Sep 17 00:00:00 2001 From: Crystal Melting Dot Date: Thu, 14 Jul 2022 19:54:56 +0300 Subject: [PATCH 01/14] escape column name --- src/norm/model.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/norm/model.nim b/src/norm/model.nim index 0021e347..9957983d 100644 --- a/src/norm/model.nim +++ b/src/norm/model.nim @@ -44,7 +44,7 @@ func table*(T: typedesc[Model]): string = func col*(T: typedesc[Model], fld: string): string = ## Get column name for a `Model`_ field, which is just the field name. - fld + fld.escape func col*[T: Model](obj: T, fld: string): string = ## Get column name for a `Model`_ instance field. From dd67ee13199d2c853e45f47310823ff452ab8e39 Mon Sep 17 00:00:00 2001 From: Crystal Melting Dot Date: Thu, 14 Jul 2022 22:40:17 +0300 Subject: [PATCH 02/14] not escape, quote --- src/norm/model.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/norm/model.nim b/src/norm/model.nim index 9957983d..b180e8e3 100644 --- a/src/norm/model.nim +++ b/src/norm/model.nim @@ -44,7 +44,7 @@ func table*(T: typedesc[Model]): string = func col*(T: typedesc[Model], fld: string): string = ## Get column name for a `Model`_ field, which is just the field name. - fld.escape + "\"" & fld & "\"" func col*[T: Model](obj: T, fld: string): string = ## Get column name for a `Model`_ instance field. From 363d225a334337b6a05a7af1e8d19a02d84601ea Mon Sep 17 00:00:00 2001 From: Crystal Melting Dot Date: Mon, 18 Jul 2022 21:40:36 +0300 Subject: [PATCH 03/14] test for quoted fields in tmodel --- tests/common/tmodel.nim | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/common/tmodel.nim b/tests/common/tmodel.nim index f72e806f..7b008edd 100644 --- a/tests/common/tmodel.nim +++ b/tests/common/tmodel.nim @@ -16,26 +16,26 @@ suite "Getting table and columns from Model": pet = newPet("cat", toy) person = newPerson("Alice", pet) - check person.col("name") == "name" - check pet.col("species") == "species" + check person.col("name") == "\"name\"" + check pet.col("species") == "\"species\"" - check person.cols == @["name", "pet"] - check person.cols(force = true) == @["name", "pet", "id"] + check person.cols == @["\"name\"", "\"pet\""] + check person.cols(force = true) == @["\"name\"", "\"pet\"", "\"id\""] - check person.fCol("name") == """"Person".name""" - check pet.fCol("species") == """"Pet".species""" + check person.fCol("name") == """"Person"."name"""" + check pet.fCol("species") == """"Pet"."species"""" check person.rfCols == @[ - """"Person".name""", - """"Person".pet""", - """"pet".species""", - """"pet".favToy""", - """"pet_favToy".price""", - """"pet_favToy".id""", - """"pet".id""", - """"Person".id""" + """"Person"."name"""", + """"Person"."pet"""", + """"pet"."species"""", + """"pet"."favToy"""", + """"pet_favToy"."price"""", + """"pet_favToy"."id"""", + """"pet"."id"""", + """"Person"."id"""" ] - check toy.rfCols == @[""""Toy".price""", """"Toy".id"""] + check toy.rfCols == @[""""Toy"."price"""", """"Toy"."id""""] test "Join groups": let @@ -44,8 +44,8 @@ suite "Getting table and columns from Model": person = newPerson("Alice", pet) check person.joinGroups == @[ - (""""Pet"""", """"pet"""", """"Person".pet""", """"pet".id"""), - (""""Toy"""", """"pet_favToy"""", """"pet".favToy""", """"pet_favToy".id""") + (""""Pet"""", """"pet"""", """"Person"."pet"""", """"pet"."id""""), + (""""Toy"""", """"pet_favToy"""", """"pet"."favToy"""", """"pet_favToy"."id"""") ] test "When related model has field with the type of the given model, expect name of that field as a string": From 9c677bc622b4f86de2913fb6d0d03086e59f6a85 Mon Sep 17 00:00:00 2001 From: Crystal Melting Dot Date: Tue, 19 Jul 2022 12:46:10 +0300 Subject: [PATCH 04/14] Add changelog entry and bump version --- changelog.md | 3 +++ norm.nimble | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 9071829d..838b1b9e 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,9 @@ - [t]—test suite improvement - [d]—docs improvement +## 2.5.1 (July 19, 2022) + +- [f] Usage of SQL keywords as field names is now possible by quoting them in the resulting query. ## 2.5.0 (July 8, 2022) diff --git a/norm.nimble b/norm.nimble index 0003c75a..15ac0d33 100755 --- a/norm.nimble +++ b/norm.nimble @@ -1,6 +1,6 @@ # Package -version = "2.5.0" +version = "2.5.1" author = "Constantine Molchanov" description = "Nim ORM for SQLite and PostgreSQL." license = "MIT" From 12cf790d50ef93dd51885c1afa11aff388531a83 Mon Sep 17 00:00:00 2001 From: Crystal Melting Dot Date: Tue, 19 Jul 2022 12:54:11 +0300 Subject: [PATCH 05/14] ok, no version bump, then --- norm.nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/norm.nimble b/norm.nimble index 15ac0d33..0003c75a 100755 --- a/norm.nimble +++ b/norm.nimble @@ -1,6 +1,6 @@ # Package -version = "2.5.1" +version = "2.5.0" author = "Constantine Molchanov" description = "Nim ORM for SQLite and PostgreSQL." license = "MIT" From 44af6816d676e946d558332787cab431e282bf53 Mon Sep 17 00:00:00 2001 From: Philipp Doerner Date: Mon, 22 Aug 2022 18:53:08 +0200 Subject: [PATCH 06/14] #159 fixed tdbtypes test for postgres The field there now requires quotation marks around itself. This is likely because in the SELECT bit of the query the fields are also provided with quotation marks. --- tests/postgres/tdbtypes.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/postgres/tdbtypes.nim b/tests/postgres/tdbtypes.nim index 7aa24187..04fd491b 100644 --- a/tests/postgres/tdbtypes.nim +++ b/tests/postgres/tdbtypes.nim @@ -4,7 +4,6 @@ import norm/[model, postgres, types] import ../models - const dbHost = "postgres" dbUser = "postgres" @@ -33,7 +32,7 @@ suite "Import dbTypes from norm/private/postgres/dbtypes": test "dbValue[DateTime] is imported": let users = @[newUser()].dup: - dbConn.select("""lastLogin <= $1""", ?now()) + dbConn.select(""""lastLogin" <= $1""", ?now()) check len(users) == 0 From 5638632b4a111c889f639a6c2d5d03bf7f1130ba Mon Sep 17 00:00:00 2001 From: Philipp Doerner Date: Mon, 22 Aug 2022 18:54:03 +0200 Subject: [PATCH 07/14] #159 fixed case-sensitive test error On linux, databases tend to be case-sensitive with their tests. This test failed in part because the column is `userId` not `userid` --- tests/postgres/tfkpragma.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/postgres/tfkpragma.nim b/tests/postgres/tfkpragma.nim index ddc0be57..1af313b1 100644 --- a/tests/postgres/tfkpragma.nim +++ b/tests/postgres/tfkpragma.nim @@ -70,6 +70,6 @@ suite "``fk`` pragma": for inpCustomer in inpCustomers.mitems: dbConn.insert inpCustomer - dbConn.select(outCustomers, """"userid" = $1""", userA.id) + dbConn.select(outCustomers, """"userId" = $1""", userA.id) check outCustomers === inpCustomers[0..^2] From 31e113d64c7c188f3f4b1b59eef8b95d486dbdf4 Mon Sep 17 00:00:00 2001 From: Philipp Doerner Date: Mon, 22 Aug 2022 18:54:58 +0200 Subject: [PATCH 08/14] #159 fixed createTables not escaping field names properly In the 3 ways a Foreign Key Constraint may be generated the field does not get escaped. This causes issues in the tests. --- src/norm/postgres.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/norm/postgres.nim b/src/norm/postgres.nim index 62351be7..10a63698 100644 --- a/src/norm/postgres.nim +++ b/src/norm/postgres.nim @@ -101,7 +101,7 @@ proc createTables*[T: Model](dbConn; obj: T) = colShmParts.add "UNIQUE" if val.isModel: - var fkGroup = "FOREIGN KEY($#) REFERENCES $#($#)" % + var fkGroup = """FOREIGN KEY("$#") REFERENCES $#($#)""" % [obj.col(fld), typeof(get val.model).table, typeof(get val.model).col("id")] when obj.dot(fld).hasCustomPragma(onDelete): @@ -120,9 +120,9 @@ proc createTables*[T: Model](dbConn; obj: T) = const selfTableName = '"' & T.getCustomPragmaVal(tableName) & '"' else: const selfTableName = '"' & $T & '"' - fkGroups.add "FOREIGN KEY ($#) REFERENCES $#(id)" % [fld, selfTableName] + fkGroups.add """FOREIGN KEY ("$#") REFERENCES $#(id)""" % [fld, selfTableName] else: - fkGroups.add "FOREIGN KEY ($#) REFERENCES $#(id)" % [fld, (obj.dot(fld).getCustomPragmaVal(fk)).table] + fkGroups.add """FOREIGN KEY ("$#") REFERENCES $#(id)""" % [fld, (obj.dot(fld).getCustomPragmaVal(fk)).table] colGroups.add colShmParts.join(" ") From 146c0ab3f424cfc33462439b2b80375c22f76b49 Mon Sep 17 00:00:00 2001 From: Philipp Doerner Date: Mon, 22 Aug 2022 18:55:56 +0200 Subject: [PATCH 09/14] #159 escaped fieldnames in tests This appears to now be mandatorily necessary --- tests/postgres/tfkpragma.nim | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/postgres/tfkpragma.nim b/tests/postgres/tfkpragma.nim index 1af313b1..f6317611 100644 --- a/tests/postgres/tfkpragma.nim +++ b/tests/postgres/tfkpragma.nim @@ -1,9 +1,11 @@ -import std/[unittest, times, strutils] +import std/[unittest, times, strutils, logging] import norm/[model, postgres] import ../models +addHandler(newConsoleLogger(levelThreshold = lvlDebug)) + const dbHost = "postgres" @@ -41,8 +43,8 @@ suite "``fk`` pragma": check customer.id > 0 let - userRows = dbConn.getAllRows(sql"""SELECT lastLogin, id FROM "User"""") - customerRows = dbConn.getAllRows(sql"""SELECT userId, email, id FROM "Customer"""") + userRows = dbConn.getAllRows(sql"""SELECT "lastLogin", "id" FROM "User" """) + customerRows = dbConn.getAllRows(sql"""SELECT "userId", "email", "id" FROM "Customer" """) check userRows.len == 1 check userRows[0][1] == ?user.id From 63a14f5a4bb167ef4c88f1c477a7cf3890a3f60a Mon Sep 17 00:00:00 2001 From: Philipp Doerner Date: Mon, 22 Aug 2022 19:21:08 +0200 Subject: [PATCH 10/14] #159 Removed quotes for foreign key constraints based on model fields For some reason the tests of tcount fail, because the model in there has another model in it, which generates an FK field that then looks like this: ""favToy"" Which causes SQL errors. --- src/norm/postgres.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/norm/postgres.nim b/src/norm/postgres.nim index 10a63698..0393b524 100644 --- a/src/norm/postgres.nim +++ b/src/norm/postgres.nim @@ -101,7 +101,7 @@ proc createTables*[T: Model](dbConn; obj: T) = colShmParts.add "UNIQUE" if val.isModel: - var fkGroup = """FOREIGN KEY("$#") REFERENCES $#($#)""" % + var fkGroup = """FOREIGN KEY($#) REFERENCES $#($#)""" % [obj.col(fld), typeof(get val.model).table, typeof(get val.model).col("id")] when obj.dot(fld).hasCustomPragma(onDelete): From efe9499f76e1037a9ee1a14c54986f7e41811672 Mon Sep 17 00:00:00 2001 From: Philipp Doerner Date: Mon, 22 Aug 2022 19:27:11 +0200 Subject: [PATCH 11/14] Apparently the FK field and ONLY the FK field "favToy" must be in quotation marks. Why that is I have no idea. --- tests/postgres/trows.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/postgres/trows.nim b/tests/postgres/trows.nim index dacf3457..6c40e53f 100644 --- a/tests/postgres/trows.nim +++ b/tests/postgres/trows.nim @@ -1,5 +1,6 @@ import std/[unittest, with, strutils, sugar, options] + import norm/[model, postgres] import ../models @@ -67,7 +68,7 @@ suite "Row CRUD": let personRows = dbConn.getAllRows(sql"""SELECT name, pet, id FROM "Person"""") - petRows = dbConn.getAllRows(sql"""SELECT species, favToy, id FROM "Pet"""") + petRows = dbConn.getAllRows(sql"""SELECT species, "favToy", id FROM "Pet"""") toyRows = dbConn.getAllRows(sql"""SELECT price, id FROM "Toy"""") check personRows.len == 1 @@ -219,7 +220,7 @@ suite "Row CRUD": let personRow = get dbConn.getRow(sql"""SELECT name, pet, id FROM "Person" WHERE id = $1""", person.id) - petRow = get dbConn.getRow(sql"""SELECT species, favToy, id FROM "Pet" WHERE id = $1""", pet.id) + petRow = get dbConn.getRow(sql"""SELECT species, "favToy", id FROM "Pet" WHERE id = $1""", pet.id) toyRow = get dbConn.getRow(sql"""SELECT price, id FROM "Toy" WHERE id = $1""", pet.favToy.id) check personRow == @[?"Bob", ?pet.id, ?person.id] From bec9c0f285d95760f4547ecacd2b487a593f5daa Mon Sep 17 00:00:00 2001 From: Philipp Doerner Date: Mon, 22 Aug 2022 19:34:38 +0200 Subject: [PATCH 12/14] The field comparison is case sensitive for some reason? --- tests/postgres/ttables.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/postgres/ttables.nim b/tests/postgres/ttables.nim index 3f4bbc8a..1ebc8b86 100644 --- a/tests/postgres/ttables.nim +++ b/tests/postgres/ttables.nim @@ -56,7 +56,7 @@ suite "Table creation": check dbConn.getAllRows(qry, "FurnitureTable") == @[ @[?"id", ?"bigint"], - @[?"legcount", ?dftDbInt] + @[?"legCount", ?dftDbInt] ] test "Create tables": @@ -80,7 +80,7 @@ suite "Table creation": ] check dbConn.getAllRows(qry, "Pet") == @[ - @[?"favtoy", ?"bigint"], + @[?"favToy", ?"bigint"], @[?"id", ?"bigint"], @[?"species", ?"text"] ] From 5ebf1d30279ac18f53b02ab35b1c3ba936db41d4 Mon Sep 17 00:00:00 2001 From: Philipp Doerner Date: Tue, 23 Aug 2022 07:22:37 +0200 Subject: [PATCH 13/14] #159 Removed some unnecessary changes I made for debugging --- changelog.md | 1 - tests/postgres/tfkpragma.nim | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index 91bb38b6..469b6730 100644 --- a/changelog.md +++ b/changelog.md @@ -7,7 +7,6 @@ - [t]—test suite improvement - [d]—docs improvement - ## 2.5.2 (WIP) - [r] Logging: refactored `log` module to not trigger warnings when `normDebug` is not defined. diff --git a/tests/postgres/tfkpragma.nim b/tests/postgres/tfkpragma.nim index f6317611..3e17a78c 100644 --- a/tests/postgres/tfkpragma.nim +++ b/tests/postgres/tfkpragma.nim @@ -1,12 +1,9 @@ -import std/[unittest, times, strutils, logging] +import std/[unittest, times, strutils] import norm/[model, postgres] import ../models -addHandler(newConsoleLogger(levelThreshold = lvlDebug)) - - const dbHost = "postgres" dbUser = "postgres" From fc6ade89ed76fb3ec81ffdbb1d5a165e6dec864a Mon Sep 17 00:00:00 2001 From: Philipp Doerner Date: Tue, 23 Aug 2022 12:35:51 +0200 Subject: [PATCH 14/14] Removed dangerous inconsistent behaviour for Foreign Key constraint generation I do not know whether obj.col(fld) actually is correct code, but it *does* run through all tests. --- src/norm/postgres.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/norm/postgres.nim b/src/norm/postgres.nim index 6e7baaff..72360c98 100644 --- a/src/norm/postgres.nim +++ b/src/norm/postgres.nim @@ -123,9 +123,9 @@ proc createTables*[T: Model](dbConn; obj: T) = const selfTableName = '"' & T.getCustomPragmaVal(tableName) & '"' else: const selfTableName = '"' & $T & '"' - fkGroups.add """FOREIGN KEY ("$#") REFERENCES $#(id)""" % [fld, selfTableName] + fkGroups.add """FOREIGN KEY ($#) REFERENCES $#(id)""" % [obj.col(fld), selfTableName] else: - fkGroups.add """FOREIGN KEY ("$#") REFERENCES $#(id)""" % [fld, (obj.dot(fld).getCustomPragmaVal(fk)).table] + fkGroups.add """FOREIGN KEY ($#) REFERENCES $#(id)""" % [obj.col(fld), (obj.dot(fld).getCustomPragmaVal(fk)).table] colGroups.add colShmParts.join(" ")