Fixed #30240 -- Added SHA1, SHA224, SHA256, SHA384, and SHA512 database functions.

Thanks Mariusz Felisiak and Tim Graham for reviews.
This commit is contained in:
Nick Pope 2019-03-20 18:30:43 +00:00 committed by Mariusz Felisiak
parent 0193bf874f
commit 0b70985f42
13 changed files with 439 additions and 19 deletions

View file

@ -0,0 +1,13 @@
from unittest import mock
from django.db import migrations
try:
from django.contrib.postgres.operations import CryptoExtension
except ImportError:
CryptoExtension = mock.Mock()
class Migration(migrations.Migration):
# Required for the SHA database functions.
operations = [CryptoExtension()]

View file

@ -0,0 +1,77 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('db_functions', '0001_setup_extensions'),
]
operations = [
migrations.CreateModel(
name='Author',
fields=[
('name', models.CharField(max_length=50)),
('alias', models.CharField(max_length=50, null=True, blank=True)),
('goes_by', models.CharField(max_length=50, null=True, blank=True)),
('age', models.PositiveSmallIntegerField(default=30)),
],
),
migrations.CreateModel(
name='Article',
fields=[
('authors', models.ManyToManyField('db_functions.Author', related_name='articles')),
('title', models.CharField(max_length=50)),
('summary', models.CharField(max_length=200, null=True, blank=True)),
('text', models.TextField()),
('written', models.DateTimeField()),
('published', models.DateTimeField(null=True, blank=True)),
('updated', models.DateTimeField(null=True, blank=True)),
('views', models.PositiveIntegerField(default=0)),
],
),
migrations.CreateModel(
name='Fan',
fields=[
('name', models.CharField(max_length=50)),
('age', models.PositiveSmallIntegerField(default=30)),
('author', models.ForeignKey('db_functions.Author', models.CASCADE, related_name='fans')),
('fan_since', models.DateTimeField(null=True, blank=True)),
],
),
migrations.CreateModel(
name='DTModel',
fields=[
('name', models.CharField(max_length=32)),
('start_datetime', models.DateTimeField(null=True, blank=True)),
('end_datetime', models.DateTimeField(null=True, blank=True)),
('start_date', models.DateField(null=True, blank=True)),
('end_date', models.DateField(null=True, blank=True)),
('start_time', models.TimeField(null=True, blank=True)),
('end_time', models.TimeField(null=True, blank=True)),
('duration', models.DurationField(null=True, blank=True)),
],
),
migrations.CreateModel(
name='DecimalModel',
fields=[
('n1', models.DecimalField(decimal_places=2, max_digits=6)),
('n2', models.DecimalField(decimal_places=2, max_digits=6)),
],
),
migrations.CreateModel(
name='IntegerModel',
fields=[
('big', models.BigIntegerField(null=True, blank=True)),
('normal', models.IntegerField(null=True, blank=True)),
('small', models.SmallIntegerField(null=True, blank=True)),
],
),
migrations.CreateModel(
name='FloatModel',
fields=[
('f1', models.FloatField(null=True, blank=True)),
('f2', models.FloatField(null=True, blank=True)),
],
),
]

View file

@ -0,0 +1,42 @@
from django.db import connection
from django.db.models import CharField
from django.db.models.functions import SHA1
from django.test import TestCase
from django.test.utils import register_lookup
from ..models import Author
class SHA1Tests(TestCase):
@classmethod
def setUpTestData(cls):
Author.objects.bulk_create([
Author(alias='John Smith'),
Author(alias='Jordan Élena'),
Author(alias='皇帝'),
Author(alias=''),
Author(alias=None),
])
def test_basic(self):
authors = Author.objects.annotate(
sha1_alias=SHA1('alias'),
).values_list('sha1_alias', flat=True).order_by('pk')
self.assertSequenceEqual(
authors,
[
'e61a3587b3f7a142b8c7b9263c82f8119398ecb7',
'0781e0745a2503e6ded05ed5bc554c421d781b0c',
'198d15ea139de04060caf95bc3e0ec5883cba881',
'da39a3ee5e6b4b0d3255bfef95601890afd80709',
'da39a3ee5e6b4b0d3255bfef95601890afd80709'
if connection.features.interprets_empty_strings_as_nulls else None,
],
)
def test_transform(self):
with register_lookup(CharField, SHA1):
authors = Author.objects.filter(
alias__sha1='e61a3587b3f7a142b8c7b9263c82f8119398ecb7',
).values_list('alias', flat=True)
self.assertSequenceEqual(authors, ['John Smith'])

View file

@ -0,0 +1,53 @@
import unittest
from django.db import connection
from django.db.models import CharField
from django.db.models.functions import SHA224
from django.db.utils import NotSupportedError
from django.test import TestCase
from django.test.utils import register_lookup
from ..models import Author
class SHA224Tests(TestCase):
@classmethod
def setUpTestData(cls):
Author.objects.bulk_create([
Author(alias='John Smith'),
Author(alias='Jordan Élena'),
Author(alias='皇帝'),
Author(alias=''),
Author(alias=None),
])
@unittest.skipIf(connection.vendor == 'oracle', "Oracle doesn't support SHA224.")
def test_basic(self):
authors = Author.objects.annotate(
sha224_alias=SHA224('alias'),
).values_list('sha224_alias', flat=True).order_by('pk')
self.assertSequenceEqual(
authors,
[
'a61303c220731168452cb6acf3759438b1523e768f464e3704e12f70',
'2297904883e78183cb118fc3dc21a610d60daada7b6ebdbc85139f4d',
'eba942746e5855121d9d8f79e27dfdebed81adc85b6bf41591203080',
'd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f',
'd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f'
if connection.features.interprets_empty_strings_as_nulls else None,
],
)
@unittest.skipIf(connection.vendor == 'oracle', "Oracle doesn't support SHA224.")
def test_transform(self):
with register_lookup(CharField, SHA224):
authors = Author.objects.filter(
alias__sha224='a61303c220731168452cb6acf3759438b1523e768f464e3704e12f70',
).values_list('alias', flat=True)
self.assertSequenceEqual(authors, ['John Smith'])
@unittest.skipUnless(connection.vendor == 'oracle', "Oracle doesn't support SHA224.")
def test_unsupported(self):
msg = 'SHA224 is not supported on Oracle.'
with self.assertRaisesMessage(NotSupportedError, msg):
Author.objects.annotate(sha224_alias=SHA224('alias')).first()

View file

@ -0,0 +1,42 @@
from django.db import connection
from django.db.models import CharField
from django.db.models.functions import SHA256
from django.test import TestCase
from django.test.utils import register_lookup
from ..models import Author
class SHA256Tests(TestCase):
@classmethod
def setUpTestData(cls):
Author.objects.bulk_create([
Author(alias='John Smith'),
Author(alias='Jordan Élena'),
Author(alias='皇帝'),
Author(alias=''),
Author(alias=None),
])
def test_basic(self):
authors = Author.objects.annotate(
sha256_alias=SHA256('alias'),
).values_list('sha256_alias', flat=True).order_by('pk')
self.assertSequenceEqual(
authors,
[
'ef61a579c907bbed674c0dbcbcf7f7af8f851538eef7b8e58c5bee0b8cfdac4a',
'6e4cce20cd83fc7c202f21a8b2452a68509cf24d1c272a045b5e0cfc43f0d94e',
'3ad2039e3ec0c88973ae1c0fce5a3dbafdd5a1627da0a92312c54ebfcf43988e',
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
if connection.features.interprets_empty_strings_as_nulls else None,
],
)
def test_transform(self):
with register_lookup(CharField, SHA256):
authors = Author.objects.filter(
alias__sha256='ef61a579c907bbed674c0dbcbcf7f7af8f851538eef7b8e58c5bee0b8cfdac4a',
).values_list('alias', flat=True)
self.assertSequenceEqual(authors, ['John Smith'])

View file

@ -0,0 +1,44 @@
from django.db import connection
from django.db.models import CharField
from django.db.models.functions import SHA384
from django.test import TestCase
from django.test.utils import register_lookup
from ..models import Author
class SHA384Tests(TestCase):
@classmethod
def setUpTestData(cls):
Author.objects.bulk_create([
Author(alias='John Smith'),
Author(alias='Jordan Élena'),
Author(alias='皇帝'),
Author(alias=''),
Author(alias=None),
])
def test_basic(self):
authors = Author.objects.annotate(
sha384_alias=SHA384('alias'),
).values_list('sha384_alias', flat=True).order_by('pk')
self.assertSequenceEqual(
authors,
[
'9df976bfbcf96c66fbe5cba866cd4deaa8248806f15b69c4010a404112906e4ca7b57e53b9967b80d77d4f5c2982cbc8',
'72202c8005492016cc670219cce82d47d6d2d4273464c742ab5811d691b1e82a7489549e3a73ffa119694f90678ba2e3',
'eda87fae41e59692c36c49e43279c8111a00d79122a282a944e8ba9a403218f049a48326676a43c7ba378621175853b0',
'38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b',
'38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b'
if connection.features.interprets_empty_strings_as_nulls else None,
],
)
def test_transform(self):
with register_lookup(CharField, SHA384):
authors = Author.objects.filter(
alias__sha384=(
'9df976bfbcf96c66fbe5cba866cd4deaa8248806f15b69c4010a404112906e4ca7b57e53b9967b80d77d4f5c2982cbc8'
),
).values_list('alias', flat=True)
self.assertSequenceEqual(authors, ['John Smith'])

View file

@ -0,0 +1,51 @@
from django.db import connection
from django.db.models import CharField
from django.db.models.functions import SHA512
from django.test import TestCase
from django.test.utils import register_lookup
from ..models import Author
class SHA512Tests(TestCase):
@classmethod
def setUpTestData(cls):
Author.objects.bulk_create([
Author(alias='John Smith'),
Author(alias='Jordan Élena'),
Author(alias='皇帝'),
Author(alias=''),
Author(alias=None),
])
def test_basic(self):
authors = Author.objects.annotate(
sha512_alias=SHA512('alias'),
).values_list('sha512_alias', flat=True).order_by('pk')
self.assertSequenceEqual(
authors,
[
'ed014a19bb67a85f9c8b1d81e04a0e7101725be8627d79d02ca4f3bd803f33cf'
'3b8fed53e80d2a12c0d0e426824d99d110f0919298a5055efff040a3fc091518',
'b09c449f3ba49a32ab44754982d4749ac938af293e4af2de28858858080a1611'
'2b719514b5e48cb6ce54687e843a4b3e69a04cdb2a9dc99c3b99bdee419fa7d0',
'b554d182e25fb487a3f2b4285bb8672f98956b5369138e681b467d1f079af116'
'172d88798345a3a7666faf5f35a144c60812d3234dcd35f444624f2faee16857',
'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce'
'47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e',
'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce'
'47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e'
if connection.features.interprets_empty_strings_as_nulls else None,
],
)
def test_transform(self):
with register_lookup(CharField, SHA512):
authors = Author.objects.filter(
alias__sha512=(
'ed014a19bb67a85f9c8b1d81e04a0e7101725be8627d79d02ca4f3bd8'
'03f33cf3b8fed53e80d2a12c0d0e426824d99d110f0919298a5055eff'
'f040a3fc091518'
),
).values_list('alias', flat=True)
self.assertSequenceEqual(authors, ['John Smith'])