|
1 | 1 | import decimal |
| 2 | +from unittest import TestCase |
2 | 3 |
|
3 | | -from piccolo.testing.test_case import TableTest |
| 4 | +from piccolo.columns.column_types import JSON, ForeignKey, Serial, Varchar |
| 5 | +from piccolo.table import Table |
| 6 | +from piccolo.testing.test_case import AsyncTableTest, TableTest |
4 | 7 | from tests.base import engine_is |
5 | 8 | from tests.example_apps.music.tables import ( |
6 | 9 | Band, |
|
18 | 21 |
|
19 | 22 | class TestCreateJoin: |
20 | 23 | def test_create_join(self): |
| 24 | + """ |
| 25 | + A simple test to make sure tables with foreign keys can be created. |
| 26 | + """ |
21 | 27 | for table in TABLES: |
22 | 28 | table.create_table().run_sync() |
23 | 29 |
|
@@ -74,9 +80,10 @@ def setUp(self): |
74 | 80 | ) |
75 | 81 | instrument.save().run_sync() |
76 | 82 |
|
77 | | - ########################################################################### |
78 | 83 |
|
79 | | - def test_join(self): |
| 84 | +class TestSelectJoin(TestJoin): |
| 85 | + |
| 86 | + def test_select_join(self): |
80 | 87 | select_query = Concert.select( |
81 | 88 | Concert.band_1.name, |
82 | 89 | Concert.band_2.name, |
@@ -211,25 +218,6 @@ def test_select_all_columns_deep(self): |
211 | 218 | }, |
212 | 219 | ) |
213 | 220 |
|
214 | | - def test_proxy_columns(self): |
215 | | - """ |
216 | | - Make sure that ``proxy_columns`` are set correctly. |
217 | | -
|
218 | | - There used to be a bug which meant queries got slower over time: |
219 | | -
|
220 | | - https://github.com/piccolo-orm/piccolo/issues/691 |
221 | | -
|
222 | | - """ |
223 | | - # We call it multiple times to make sure it doesn't change with time. |
224 | | - for _ in range(2): |
225 | | - self.assertEqual( |
226 | | - len(Concert.band_1._.manager._foreign_key_meta.proxy_columns), |
227 | | - 2, |
228 | | - ) |
229 | | - self.assertEqual( |
230 | | - len(Concert.band_1._foreign_key_meta.proxy_columns), 4 |
231 | | - ) |
232 | | - |
233 | 221 | def test_select_all_columns_root(self): |
234 | 222 | """ |
235 | 223 | Make sure that using ``all_columns`` at the root doesn't interfere |
@@ -343,7 +331,29 @@ def test_select_all_columns_exclude(self): |
343 | 331 | }, |
344 | 332 | ) |
345 | 333 |
|
346 | | - ########################################################################### |
| 334 | + |
| 335 | +class TestProxyColumns(TestCase): |
| 336 | + def test_proxy_columns(self): |
| 337 | + """ |
| 338 | + Make sure that ``proxy_columns`` are set correctly. |
| 339 | +
|
| 340 | + There used to be a bug which meant queries got slower over time: |
| 341 | +
|
| 342 | + https://github.com/piccolo-orm/piccolo/issues/691 |
| 343 | +
|
| 344 | + """ |
| 345 | + # We call it multiple times to make sure it doesn't change with time. |
| 346 | + for _ in range(2): |
| 347 | + self.assertEqual( |
| 348 | + len(Concert.band_1._.manager._foreign_key_meta.proxy_columns), |
| 349 | + 2, |
| 350 | + ) |
| 351 | + self.assertEqual( |
| 352 | + len(Concert.band_1._foreign_key_meta.proxy_columns), 4 |
| 353 | + ) |
| 354 | + |
| 355 | + |
| 356 | +class TestObjectsJoin(TestJoin): |
347 | 357 |
|
348 | 358 | def test_objects_nested(self): |
349 | 359 | """ |
@@ -413,52 +423,6 @@ def test_objects__all_related__deep(self): |
413 | 423 | self.assertIsInstance(ticket.concert.band_1.manager, Manager) |
414 | 424 | self.assertIsInstance(ticket.concert.band_2.manager, Manager) |
415 | 425 |
|
416 | | - def test_objects_nested_with_load_json(self): |
417 | | - """ |
418 | | - Make sure that nested objects works alongside ``load_json`` (i.e. the |
419 | | - JSON on nested objects gets loaded). |
420 | | -
|
421 | | - https://github.com/piccolo-orm/piccolo/issues/1383 |
422 | | -
|
423 | | - """ |
424 | | - instrument = ( |
425 | | - Instrument.objects(Instrument.recording_studio) |
426 | | - .output(load_json=True) |
427 | | - .first() |
428 | | - .run_sync() |
429 | | - ) |
430 | | - assert instrument is not None |
431 | | - self.assertDictEqual( |
432 | | - instrument.recording_studio.facilities, |
433 | | - {"restaurant": True}, |
434 | | - ) |
435 | | - |
436 | | - def test_objects_nested_with_load_json_null(self): |
437 | | - """ |
438 | | - Make sure that nested objects works alongside ``load_json``, when |
439 | | - the nested object has a null value for a JSON column. |
440 | | -
|
441 | | - https://github.com/piccolo-orm/piccolo/issues/1391 |
442 | | -
|
443 | | - """ |
444 | | - RecordingStudio.update( |
445 | | - { |
446 | | - RecordingStudio.facilities: None, |
447 | | - }, |
448 | | - force=True, |
449 | | - ).run_sync() |
450 | | - |
451 | | - instrument = ( |
452 | | - Instrument.objects(Instrument.recording_studio) |
453 | | - .output(load_json=True) |
454 | | - .first() |
455 | | - .run_sync() |
456 | | - ) |
457 | | - assert instrument is not None |
458 | | - self.assertIsNone( |
459 | | - instrument.recording_studio.facilities, |
460 | | - ) |
461 | | - |
462 | 426 | def test_objects_prefetch_clause(self): |
463 | 427 | """ |
464 | 428 | Make sure that ``prefetch`` clause works correctly. |
@@ -562,3 +526,96 @@ def test_objects_prefetch_db_column_name(self): |
562 | 526 | signing = Signing.objects().prefetch(Signing.with_).first().run_sync() |
563 | 527 | assert signing is not None |
564 | 528 | self.assertIsInstance(signing.with_, Band) |
| 529 | + |
| 530 | + |
| 531 | +class TestObjectsNestedLoadJSON(TestJoin): |
| 532 | + def test_objects_nested_with_load_json(self): |
| 533 | + """ |
| 534 | + Make sure that nested objects works alongside ``load_json`` (i.e. the |
| 535 | + JSON on nested objects gets loaded). |
| 536 | +
|
| 537 | + https://github.com/piccolo-orm/piccolo/issues/1383 |
| 538 | +
|
| 539 | + """ |
| 540 | + instrument = ( |
| 541 | + Instrument.objects(Instrument.recording_studio) |
| 542 | + .output(load_json=True) |
| 543 | + .first() |
| 544 | + .run_sync() |
| 545 | + ) |
| 546 | + assert instrument is not None |
| 547 | + self.assertDictEqual( |
| 548 | + instrument.recording_studio.facilities, |
| 549 | + {"restaurant": True}, |
| 550 | + ) |
| 551 | + |
| 552 | + def test_objects_nested_with_load_json_null(self): |
| 553 | + """ |
| 554 | + Make sure that nested objects works alongside ``load_json``, when |
| 555 | + the nested object has a null value for a JSON column. |
| 556 | +
|
| 557 | + https://github.com/piccolo-orm/piccolo/issues/1391 |
| 558 | +
|
| 559 | + """ |
| 560 | + RecordingStudio.update( |
| 561 | + { |
| 562 | + RecordingStudio.facilities: None, |
| 563 | + }, |
| 564 | + force=True, |
| 565 | + ).run_sync() |
| 566 | + |
| 567 | + instrument = ( |
| 568 | + Instrument.objects(Instrument.recording_studio) |
| 569 | + .output(load_json=True) |
| 570 | + .first() |
| 571 | + .run_sync() |
| 572 | + ) |
| 573 | + assert instrument is not None |
| 574 | + self.assertIsNone( |
| 575 | + instrument.recording_studio.facilities, |
| 576 | + ) |
| 577 | + |
| 578 | + |
| 579 | +class TableA(Table): |
| 580 | + id = Serial(primary_key=True) |
| 581 | + name = Varchar() |
| 582 | + |
| 583 | + |
| 584 | +class TableB(Table): |
| 585 | + data = JSON() |
| 586 | + table_a = ForeignKey(TableA, null=False) |
| 587 | + |
| 588 | + |
| 589 | +class TestObjectsNestedLoadJSONArray(AsyncTableTest): |
| 590 | + tables = [TableA, TableB] |
| 591 | + |
| 592 | + async def test_objects_nested_with_load_json_array(self): |
| 593 | + """ |
| 594 | + Make sure that nested objects works alongside ``load_json``, when |
| 595 | + the parent object has a JSON column, and it contains an array value. |
| 596 | +
|
| 597 | + https://github.com/piccolo-orm/piccolo/issues/1399#issuecomment-4864444701 |
| 598 | +
|
| 599 | + The problem was because we already loaded the JSON string on the top |
| 600 | + level row, and then were trying to load it again in |
| 601 | + `make_nested_object`. |
| 602 | +
|
| 603 | + """ # noqa: E501 |
| 604 | + table_a = TableA() |
| 605 | + await table_a.save() |
| 606 | + |
| 607 | + data = ["a", "b", "c"] |
| 608 | + table_b = TableB(data=data, table_a=table_a.id) |
| 609 | + await table_b.save() |
| 610 | + |
| 611 | + # Without prefetch: |
| 612 | + row = await TableB.objects().output(load_json=True).first() |
| 613 | + assert row |
| 614 | + assert row.data == data |
| 615 | + |
| 616 | + # With prefetch: |
| 617 | + row = ( |
| 618 | + await TableB.objects(TableB.table_a).output(load_json=True).first() |
| 619 | + ) |
| 620 | + assert row |
| 621 | + assert row.data == data |
0 commit comments