Skip to content

Commit c6e9445

Browse files
Fix issue #656 - typo in SQL UNIQUE INDEX declaration
1 parent aae57ac commit c6e9445

File tree

6 files changed

+96
-7
lines changed

6 files changed

+96
-7
lines changed

CHANGELOG.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
## Release notes
22

3-
### 0.12.0 -- Aug 23, 2019
4-
* Support TLS/SSL connections PR620
3+
### 0.12.0 -- October 1, 2019
4+
* Support secure connections with TLS (aka SSL) PR #620
55
* Convert numpy array from python object to appropriate data type if all elements are of the same type (#587) PR #608
66
* Remove expression requirement to have additional attributes (#604) PR #604
77
* Support for filepath datatype (#481) PR #603
@@ -19,7 +19,7 @@
1919
* Support for pandas and order by "KEY" (#459, #537, #538, #541) PR #534
2020
* Support file attachment datatype and configurable blob storage (#467, #475, #480, #497) PR #532
2121
* Increase default display rows (#523) PR #526
22-
* Bugfixes (#521, #205, #279, #477, #570, #581, #597, #596, #618, #633, #643, #644, #647)
22+
* Bugfixes (#521, #205, #279, #477, #570, #581, #597, #596, #618, #633, #643, #644, #647, #656)
2323

2424
### 0.11.3 -- Jul 26, 2019
2525
* Fix incompatibility with pyparsing 2.4.1 (#629) PR #631

datajoint/declare.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ def compile_foreign_key(line, context, attributes, primary_key, attr_sql, foreig
220220

221221
# declare unique index
222222
if is_unique:
223-
index_sql.append('UNIQUE INDEX ({attrs})'.format(attrs='`,`'.join(ref.primary_key)))
223+
index_sql.append('UNIQUE INDEX ({attrs})'.format(attrs=','.join("`%s`" % attr for attr in ref.primary_key)))
224224

225225

226226
def prepare_declare(definition, context):

tests/schema.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,4 +296,29 @@ class IndexRich(dj.Manual):
296296
index (first_date, value)
297297
"""
298298

299+
# Schema for issue 656
300+
@schema
301+
class ThingA(dj.Manual):
302+
definition = """
303+
a: int
304+
"""
305+
306+
307+
@schema
308+
class ThingB(dj.Manual):
309+
definition = """
310+
b1: int
311+
b2: int
312+
---
313+
b3: int
314+
"""
315+
316+
317+
@schema
318+
class ThingC(dj.Manual):
319+
definition = """
320+
-> ThingA
321+
---
322+
-> [unique, nullable] ThingB
323+
"""
299324

tests/test_connection.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def test_dj_conn():
1414
Should be able to establish a connection
1515
"""
1616
c = dj.conn(**CONN_INFO)
17-
assert c.is_connected
17+
assert_true(c.is_connected)
1818

1919

2020
def test_persistent_dj_conn():
@@ -33,8 +33,6 @@ def test_persistent_dj_conn():
3333
assert_true(c4 is c5)
3434

3535

36-
37-
3836
def test_repr():
3937
c1 = dj.conn(**CONN_INFO)
4038
assert_true('disconnected' not in repr(c1) and 'connected' in repr(c1))

tests/test_declare.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ def test_describe_indexes():
4040
s2 = declare(rel.full_table_name, rel.describe(), context)
4141
assert_equal(s1, s2)
4242

43+
@staticmethod
44+
def test_describe_dependencies():
45+
"""real_definition should match original definition"""
46+
rel = ThingC()
47+
context = inspect.currentframe().f_globals
48+
s1 = declare(rel.full_table_name, rel.definition, context)
49+
s2 = declare(rel.full_table_name, rel.describe(), context)
50+
assert_equal(s1, s2)
51+
52+
4353
@staticmethod
4454
def test_part():
4555
# Lookup and part with the same name. See issue #365

tests/test_dependencies.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from nose.tools import assert_true, assert_false, assert_equal, assert_list_equal, raises
2+
from .schema import *
3+
4+
5+
def test_nullable_dependency():
6+
"""test nullable unique foreign key"""
7+
8+
# Thing C has a nullable dependency on B whose primary key is composite
9+
a = ThingA()
10+
b = ThingB()
11+
c = ThingC()
12+
13+
# clear previous contents if any.
14+
c.delete_quick()
15+
b.delete_quick()
16+
a.delete_quick()
17+
18+
a.insert(dict(a=a) for a in range(7))
19+
20+
b.insert1(dict(b1=1, b2=1, b3=100))
21+
b.insert1(dict(b1=1, b2=2, b3=100))
22+
23+
# missing foreign key attributes = ok
24+
c.insert1(dict(a=0))
25+
c.insert1(dict(a=1, b1=33))
26+
c.insert1(dict(a=2, b2=77))
27+
28+
# unique foreign key attributes = ok
29+
c.insert1(dict(a=3, b1=1, b2=1))
30+
c.insert1(dict(a=4, b1=1, b2=2))
31+
32+
assert_true(len(c) == len(c.fetch()) == 5)
33+
34+
35+
@raises(dj.errors.DuplicateError)
36+
def test_unique_dependency():
37+
"""test nullable unique foreign key"""
38+
39+
# Thing C has a nullable dependency on B whose primary key is composite
40+
a = ThingA()
41+
b = ThingB()
42+
c = ThingC()
43+
44+
# clear previous contents if any.
45+
c.delete_quick()
46+
b.delete_quick()
47+
a.delete_quick()
48+
49+
a.insert(dict(a=a) for a in range(7))
50+
51+
b.insert1(dict(b1=1, b2=1, b3=100))
52+
b.insert1(dict(b1=1, b2=2, b3=100))
53+
54+
c.insert1(dict(a=0, b1=1, b2=1))
55+
# duplicate foreign key attributes = not ok
56+
c.insert1(dict(a=1, b1=1, b2=1))

0 commit comments

Comments
 (0)