|
1 | 1 | from dataclasses import dataclass |
2 | 2 | import timeit |
3 | 3 | import typing as t |
4 | | -from unittest.mock import patch |
5 | 4 |
|
6 | 5 | from piccolo.query.base import Query |
7 | 6 |
|
8 | | -from tests.base import DBTestCase |
| 7 | +from tests.base import DBTestCase, sqlite_only |
9 | 8 | from tests.example_app.tables import Band |
10 | 9 |
|
11 | 10 |
|
@@ -52,43 +51,62 @@ def test_frozen_select_queries(self): |
52 | 51 | ), |
53 | 52 | response=[{"name": "Pythonistas"}], |
54 | 53 | ), |
55 | | - QueryResponse( |
56 | | - query=( |
57 | | - Band.select(Band.name) |
58 | | - .where(Band.name == "Pythonistas") |
59 | | - .output(as_json=True) |
60 | | - .freeze() |
61 | | - ), |
62 | | - response='[{"name":"Pythonistas"}]', |
63 | | - ), |
64 | 54 | ] |
65 | 55 |
|
66 | 56 | for query_response in query_responses: |
67 | 57 | result = query_response.query.run_sync() |
68 | 58 | self.assertEqual(result, query_response.response) |
69 | 59 |
|
70 | | - # def test_frozen_performance(self): |
71 | | - # """ |
72 | | - # The frozen query performance should exceed the non-frozen. If not, |
73 | | - # there's a problem. |
74 | | - # """ |
75 | | - # with patch.object(Band._meta.db, "run_querystring"): |
76 | | - # pass |
77 | | - |
78 | | - # iterations = 50 |
79 | | - # query = Band.select().where(Band.name == "Pythonistas").first() |
80 | | - # query_duration = timeit.timeit( |
81 | | - # lambda: query.run_sync(), number=iterations |
82 | | - # ) |
83 | | - |
84 | | - # # patch out the actual database call ... patching the engine is |
85 | | - # # quite challenging ... |
86 | | - |
87 | | - # frozen_query = query.freeze() |
88 | | - # frozen_query_duration = timeit.timeit( |
89 | | - # lambda: frozen_query.run_sync(), number=iterations |
90 | | - # ) |
91 | | - # self.assertTrue(query_duration > frozen_query_duration) |
92 | | - |
93 | | - # def test_attribute_access(self): |
94 | | - # pass |
| 60 | + def test_output_clause(self): |
| 61 | + """ |
| 62 | + Make sure the output clause still works correctly with frozen queries. |
| 63 | + """ |
| 64 | + self.insert_rows() |
| 65 | + |
| 66 | + result = ( |
| 67 | + Band.select(Band.name) |
| 68 | + .where(Band.name == "Pythonistas") |
| 69 | + .output(as_json=True) |
| 70 | + .freeze() |
| 71 | + .run_sync() |
| 72 | + ) |
| 73 | + # Some JSON encoders have a space after the colons and some don't, |
| 74 | + # so normalise them. |
| 75 | + self.assertEqual(result.replace(" ", ""), '[{"name":"Pythonistas"}]') |
| 76 | + |
| 77 | + @sqlite_only |
| 78 | + def test_frozen_performance(self): |
| 79 | + """ |
| 80 | + The frozen query performance should exceed the non-frozen. If not, |
| 81 | + there's a problem. |
| 82 | +
|
| 83 | + Only test this on SQLite, as the latency from the database itself |
| 84 | + is more predictable than with Postgres, and the test runs quickly. |
| 85 | +
|
| 86 | + """ |
| 87 | + iterations = 50 |
| 88 | + query = Band.select().where(Band.name == "Pythonistas").first() |
| 89 | + query_duration = timeit.repeat( |
| 90 | + lambda: query.run_sync(), repeat=iterations, number=1 |
| 91 | + ) |
| 92 | + |
| 93 | + frozen_query = query.freeze() |
| 94 | + frozen_query_duration = timeit.repeat( |
| 95 | + lambda: frozen_query.run_sync(), repeat=iterations, number=1 |
| 96 | + ) |
| 97 | + |
| 98 | + # Remove the outliers before comparing |
| 99 | + self.assertTrue( |
| 100 | + sum(sorted(query_duration)[5:-5]) |
| 101 | + > sum(sorted(frozen_query_duration)[5:-5]) |
| 102 | + ) |
| 103 | + |
| 104 | + def test_attribute_access(self): |
| 105 | + """ |
| 106 | + Once frozen, you shouldn't be able to call additional methods on the |
| 107 | + query (for example `.where`). |
| 108 | + """ |
| 109 | + query = Band.select().freeze() |
| 110 | + |
| 111 | + with self.assertRaises(AttributeError): |
| 112 | + query.where(Band.name == "Pythonistas") |
0 commit comments