Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: nvarchar field filtering bug for non-ascii characters #1441

Draft
wants to merge 5 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ Changelog
0.20
====

0.20.1
------
Added
^^^^^
- NVARCHAR non-ascii char support on mssql
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just add in 0.20.0 because which is not released yet


0.20.0
------
Added
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Contributors
* Paul Serov ``@thakryptex``
* Stanislav Zmiev ``@Ovsyanka83``
* Waket Zheng ``@waketzheng``
* Mohammad Norouzi ``@mm74noroozi``

Special Thanks
==============
Expand Down
70 changes: 70 additions & 0 deletions tests/fields/test_nvarchar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from tests import testmodels_mssql as testmodels
from tortoise.contrib import test
from tortoise.exceptions import IntegrityError, OperationalError
from tortoise.exceptions import ConfigurationError

@test.requireCapability(dialect="mssql")
class TestNVARCHARFields(test.IsolatedTestCase):
tortoise_test_modules = ["tests.testmodels_mssql"]

async def test_max_length_missing(self):
with self.assertRaisesRegex(
TypeError, "missing 1 required positional argument: 'max_length'"
):
testmodels.NVARCHAR() # pylint: disable=E1120

async def test_max_length_bad(self):
with self.assertRaisesRegex(ConfigurationError, "'max_length' must be >= 1"):
testmodels.NVARCHAR(max_length=0)

async def _setUpDB(self) -> None:
try:
await super()._setUpDB()
except OperationalError:
raise test.SkipTest("Works only with MSSQLServer")

async def test_empty(self):
with self.assertRaises(IntegrityError):
await testmodels.NVARCHAR.create()

async def test_filtering(self):
testmodels.NVARCHAR.create(nvarchar="سلام").sql()

async def test_create(self):
obj0 = await testmodels.NVARCHAR.create(nvarchar="سلام")
obj = await testmodels.NVARCHAR.get(id=obj0.id)
self.assertEqual(obj.nvarchar, "سلام")
self.assertIs(obj.nvarchar_null, None)
await obj.save()
obj2 = await testmodels.NVARCHAR.get(id=obj.id)
self.assertEqual(obj, obj2)

async def test_filterUTF8Chars(self):
await testmodels.NVARCHAR.create(nvarchar="سلام")
obj = await testmodels.NVARCHAR.get(nvarchar="سلام")
self.assertIsNotNone(obj)
self.assertEqual(obj.nvarchar, "سلام")

async def test_update(self):
obj0 = await testmodels.NVARCHAR.create(nvarchar="سلام")
await testmodels.NVARCHAR.filter(id=obj0.id).update(nvarchar="non-utf8")
obj = await testmodels.NVARCHAR.get(id=obj0.id)
self.assertEqual(obj.nvarchar, "non-utf8")
self.assertIs(obj.nvarchar_null, None)

async def test_cast(self):
obj0 = await testmodels.NVARCHAR.create(nvarchar=33)
obj = await testmodels.NVARCHAR.get(id=obj0.id)
self.assertEqual(obj.nvarchar, "33")

async def test_values(self):
obj0 = await testmodels.NVARCHAR.create(nvarchar="سلام")
values = await testmodels.NVARCHAR.get(id=obj0.id).values("nvarchar")
self.assertEqual(values["nvarchar"], "سلام")

async def test_values_list(self):
obj0 = await testmodels.NVARCHAR.create(nvarchar="سلام")
values = await testmodels.NVARCHAR.get(id=obj0.id).values_list("nvarchar", flat=True)
self.assertEqual(values, "سلام")


7 changes: 7 additions & 0 deletions tests/testmodels_mssql.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from tortoise import Model, fields
from tortoise.contrib.mssql.fields import NVARCHAR

class NVARCHARFields(Model):
id = fields.IntField(pk=True)
nvarchar = NVARCHAR(max_length=255)
nvarchar_null = NVARCHAR(max_length=255,null=True)
5 changes: 5 additions & 0 deletions tortoise/contrib/mssql/field_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class NVARCHAR:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about NVarChar?

def __init__(self,value):
self._value = value
def __str__(self):
return f"N'{self._value}'"
11 changes: 11 additions & 0 deletions tortoise/contrib/mssql/fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from tortoise.fields.data import CharField
from tortoise.contrib.mssql.field_types import NVARCHAR


class NVARCHAR(CharField):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about NVarCharField?


field_type = NVARCHAR

@property
def SQL_TYPE(self) -> str:
return f"NVARCHAR({self.field.max_length})"