piccolo 1.9.0__py3-none-any.whl → 1.11.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. piccolo/__init__.py +1 -1
  2. piccolo/apps/fixtures/commands/load.py +1 -1
  3. piccolo/apps/migrations/auto/__init__.py +8 -0
  4. piccolo/apps/migrations/auto/migration_manager.py +2 -1
  5. piccolo/apps/migrations/commands/backwards.py +3 -1
  6. piccolo/apps/migrations/commands/base.py +1 -1
  7. piccolo/apps/migrations/commands/check.py +1 -1
  8. piccolo/apps/migrations/commands/clean.py +1 -1
  9. piccolo/apps/migrations/commands/forwards.py +3 -1
  10. piccolo/apps/migrations/commands/new.py +4 -2
  11. piccolo/apps/schema/commands/generate.py +2 -2
  12. piccolo/apps/shell/commands/run.py +1 -1
  13. piccolo/columns/column_types.py +56 -39
  14. piccolo/columns/defaults/base.py +1 -1
  15. piccolo/columns/defaults/date.py +9 -1
  16. piccolo/columns/defaults/interval.py +1 -0
  17. piccolo/columns/defaults/time.py +9 -1
  18. piccolo/columns/defaults/timestamp.py +1 -0
  19. piccolo/columns/defaults/uuid.py +1 -1
  20. piccolo/columns/m2m.py +7 -7
  21. piccolo/columns/operators/comparison.py +4 -0
  22. piccolo/conf/apps.py +9 -4
  23. piccolo/engine/base.py +69 -20
  24. piccolo/engine/cockroach.py +2 -3
  25. piccolo/engine/postgres.py +33 -19
  26. piccolo/engine/sqlite.py +27 -22
  27. piccolo/query/functions/__init__.py +11 -1
  28. piccolo/query/functions/datetime.py +260 -0
  29. piccolo/query/functions/string.py +45 -0
  30. piccolo/query/methods/create_index.py +1 -1
  31. piccolo/query/methods/drop_index.py +1 -1
  32. piccolo/query/methods/objects.py +7 -7
  33. piccolo/query/methods/select.py +13 -7
  34. piccolo/query/mixins.py +3 -10
  35. piccolo/schema.py +18 -11
  36. piccolo/table.py +22 -21
  37. piccolo/utils/encoding.py +5 -3
  38. {piccolo-1.9.0.dist-info → piccolo-1.11.0.dist-info}/METADATA +1 -1
  39. {piccolo-1.9.0.dist-info → piccolo-1.11.0.dist-info}/RECORD +52 -50
  40. tests/apps/migrations/auto/integration/test_migrations.py +1 -1
  41. tests/columns/test_array.py +28 -0
  42. tests/conf/test_apps.py +1 -1
  43. tests/engine/test_nested_transaction.py +2 -0
  44. tests/engine/test_transaction.py +1 -2
  45. tests/query/functions/test_datetime.py +114 -0
  46. tests/query/functions/test_string.py +34 -2
  47. tests/table/test_indexes.py +4 -2
  48. tests/utils/test_pydantic.py +70 -29
  49. {piccolo-1.9.0.dist-info → piccolo-1.11.0.dist-info}/LICENSE +0 -0
  50. {piccolo-1.9.0.dist-info → piccolo-1.11.0.dist-info}/WHEEL +0 -0
  51. {piccolo-1.9.0.dist-info → piccolo-1.11.0.dist-info}/entry_points.txt +0 -0
  52. {piccolo-1.9.0.dist-info → piccolo-1.11.0.dist-info}/top_level.txt +0 -0
@@ -4,7 +4,15 @@ import contextvars
4
4
  import typing as t
5
5
  from dataclasses import dataclass
6
6
 
7
- from piccolo.engine.base import Batch, Engine, validate_savepoint_name
7
+ from typing_extensions import Self
8
+
9
+ from piccolo.engine.base import (
10
+ BaseAtomic,
11
+ BaseBatch,
12
+ BaseTransaction,
13
+ Engine,
14
+ validate_savepoint_name,
15
+ )
8
16
  from piccolo.engine.exceptions import TransactionError
9
17
  from piccolo.query.base import DDL, Query
10
18
  from piccolo.querystring import QueryString
@@ -18,16 +26,17 @@ if t.TYPE_CHECKING: # pragma: no cover
18
26
  from asyncpg.connection import Connection
19
27
  from asyncpg.cursor import Cursor
20
28
  from asyncpg.pool import Pool
29
+ from asyncpg.transaction import Transaction
21
30
 
22
31
 
23
32
  @dataclass
24
- class AsyncBatch(Batch):
33
+ class AsyncBatch(BaseBatch):
25
34
  connection: Connection
26
35
  query: Query
27
36
  batch_size: int
28
37
 
29
38
  # Set internally
30
- _transaction = None
39
+ _transaction: t.Optional[Transaction] = None
31
40
  _cursor: t.Optional[Cursor] = None
32
41
 
33
42
  @property
@@ -36,20 +45,26 @@ class AsyncBatch(Batch):
36
45
  raise ValueError("_cursor not set")
37
46
  return self._cursor
38
47
 
48
+ @property
49
+ def transaction(self) -> Transaction:
50
+ if not self._transaction:
51
+ raise ValueError("The transaction can't be found.")
52
+ return self._transaction
53
+
39
54
  async def next(self) -> t.List[t.Dict]:
40
55
  data = await self.cursor.fetch(self.batch_size)
41
56
  return await self.query._process_results(data)
42
57
 
43
- def __aiter__(self):
58
+ def __aiter__(self: Self) -> Self:
44
59
  return self
45
60
 
46
- async def __anext__(self):
61
+ async def __anext__(self) -> t.List[t.Dict]:
47
62
  response = await self.next()
48
63
  if response == []:
49
64
  raise StopAsyncIteration()
50
65
  return response
51
66
 
52
- async def __aenter__(self):
67
+ async def __aenter__(self: Self) -> Self:
53
68
  self._transaction = self.connection.transaction()
54
69
  await self._transaction.start()
55
70
  querystring = self.query.querystrings[0]
@@ -60,9 +75,9 @@ class AsyncBatch(Batch):
60
75
 
61
76
  async def __aexit__(self, exception_type, exception, traceback):
62
77
  if exception:
63
- await self._transaction.rollback()
78
+ await self.transaction.rollback()
64
79
  else:
65
- await self._transaction.commit()
80
+ await self.transaction.commit()
66
81
 
67
82
  await self.connection.close()
68
83
 
@@ -72,7 +87,7 @@ class AsyncBatch(Batch):
72
87
  ###############################################################################
73
88
 
74
89
 
75
- class Atomic:
90
+ class Atomic(BaseAtomic):
76
91
  """
77
92
  This is useful if you want to build up a transaction programatically, by
78
93
  adding queries to it.
@@ -140,7 +155,7 @@ class Savepoint:
140
155
  )
141
156
 
142
157
 
143
- class PostgresTransaction:
158
+ class PostgresTransaction(BaseTransaction):
144
159
  """
145
160
  Used for wrapping queries in a transaction, using a context manager.
146
161
  Currently it's async only.
@@ -243,7 +258,7 @@ class PostgresTransaction:
243
258
 
244
259
  ###########################################################################
245
260
 
246
- async def __aexit__(self, exception_type, exception, traceback):
261
+ async def __aexit__(self, exception_type, exception, traceback) -> bool:
247
262
  if self._parent:
248
263
  return exception is None
249
264
 
@@ -269,7 +284,7 @@ class PostgresTransaction:
269
284
  ###############################################################################
270
285
 
271
286
 
272
- class PostgresEngine(Engine[t.Optional[PostgresTransaction]]):
287
+ class PostgresEngine(Engine[PostgresTransaction]):
273
288
  """
274
289
  Used to connect to PostgreSQL.
275
290
 
@@ -331,16 +346,10 @@ class PostgresEngine(Engine[t.Optional[PostgresTransaction]]):
331
346
  __slots__ = (
332
347
  "config",
333
348
  "extensions",
334
- "log_queries",
335
- "log_responses",
336
349
  "extra_nodes",
337
350
  "pool",
338
- "current_transaction",
339
351
  )
340
352
 
341
- engine_type = "postgres"
342
- min_version_number = 10
343
-
344
353
  def __init__(
345
354
  self,
346
355
  config: t.Dict[str, t.Any],
@@ -362,7 +371,12 @@ class PostgresEngine(Engine[t.Optional[PostgresTransaction]]):
362
371
  self.current_transaction = contextvars.ContextVar(
363
372
  f"pg_current_transaction_{database_name}", default=None
364
373
  )
365
- super().__init__()
374
+ super().__init__(
375
+ engine_type="postgres",
376
+ log_queries=log_queries,
377
+ log_responses=log_responses,
378
+ min_version_number=10,
379
+ )
366
380
 
367
381
  @staticmethod
368
382
  def _parse_raw_version_string(version_string: str) -> float:
piccolo/engine/sqlite.py CHANGED
@@ -11,7 +11,15 @@ from dataclasses import dataclass
11
11
  from decimal import Decimal
12
12
  from functools import partial, wraps
13
13
 
14
- from piccolo.engine.base import Batch, Engine, validate_savepoint_name
14
+ from typing_extensions import Self
15
+
16
+ from piccolo.engine.base import (
17
+ BaseAtomic,
18
+ BaseBatch,
19
+ BaseTransaction,
20
+ Engine,
21
+ validate_savepoint_name,
22
+ )
15
23
  from piccolo.engine.exceptions import TransactionError
16
24
  from piccolo.query.base import DDL, Query
17
25
  from piccolo.querystring import QueryString
@@ -309,7 +317,7 @@ for column_name in ("TIMESTAMP", "TIMESTAMPTZ", "DATE", "TIME"):
309
317
 
310
318
 
311
319
  @dataclass
312
- class AsyncBatch(Batch):
320
+ class AsyncBatch(BaseBatch):
313
321
  connection: Connection
314
322
  query: Query
315
323
  batch_size: int
@@ -327,16 +335,16 @@ class AsyncBatch(Batch):
327
335
  data = await self.cursor.fetchmany(self.batch_size)
328
336
  return await self.query._process_results(data)
329
337
 
330
- def __aiter__(self):
338
+ def __aiter__(self: Self) -> Self:
331
339
  return self
332
340
 
333
- async def __anext__(self):
341
+ async def __anext__(self) -> t.List[t.Dict]:
334
342
  response = await self.next()
335
343
  if response == []:
336
344
  raise StopAsyncIteration()
337
345
  return response
338
346
 
339
- async def __aenter__(self):
347
+ async def __aenter__(self: Self) -> Self:
340
348
  querystring = self.query.querystrings[0]
341
349
  template, template_args = querystring.compile_string()
342
350
 
@@ -344,7 +352,7 @@ class AsyncBatch(Batch):
344
352
  return self
345
353
 
346
354
  async def __aexit__(self, exception_type, exception, traceback):
347
- await self._cursor.close()
355
+ await self.cursor.close()
348
356
  await self.connection.close()
349
357
  return exception is not None
350
358
 
@@ -363,7 +371,7 @@ class TransactionType(enum.Enum):
363
371
  exclusive = "EXCLUSIVE"
364
372
 
365
373
 
366
- class Atomic:
374
+ class Atomic(BaseAtomic):
367
375
  """
368
376
  Usage:
369
377
 
@@ -384,9 +392,9 @@ class Atomic:
384
392
  ):
385
393
  self.engine = engine
386
394
  self.transaction_type = transaction_type
387
- self.queries: t.List[Query] = []
395
+ self.queries: t.List[t.Union[Query, DDL]] = []
388
396
 
389
- def add(self, *query: Query):
397
+ def add(self, *query: t.Union[Query, DDL]):
390
398
  self.queries += list(query)
391
399
 
392
400
  async def run(self):
@@ -434,7 +442,7 @@ class Savepoint:
434
442
  )
435
443
 
436
444
 
437
- class SQLiteTransaction:
445
+ class SQLiteTransaction(BaseTransaction):
438
446
  """
439
447
  Used for wrapping queries in a transaction, using a context manager.
440
448
  Currently it's async only.
@@ -534,7 +542,7 @@ class SQLiteTransaction:
534
542
 
535
543
  ###########################################################################
536
544
 
537
- async def __aexit__(self, exception_type, exception, traceback):
545
+ async def __aexit__(self, exception_type, exception, traceback) -> bool:
538
546
  if self._parent:
539
547
  return exception is None
540
548
 
@@ -560,16 +568,8 @@ def dict_factory(cursor, row) -> t.Dict:
560
568
  return {col[0]: row[idx] for idx, col in enumerate(cursor.description)}
561
569
 
562
570
 
563
- class SQLiteEngine(Engine[t.Optional[SQLiteTransaction]]):
564
- __slots__ = (
565
- "connection_kwargs",
566
- "current_transaction",
567
- "log_queries",
568
- "log_responses",
569
- )
570
-
571
- engine_type = "sqlite"
572
- min_version_number = 3.25
571
+ class SQLiteEngine(Engine[SQLiteTransaction]):
572
+ __slots__ = ("connection_kwargs",)
573
573
 
574
574
  def __init__(
575
575
  self,
@@ -613,7 +613,12 @@ class SQLiteEngine(Engine[t.Optional[SQLiteTransaction]]):
613
613
  f"sqlite_current_transaction_{path}", default=None
614
614
  )
615
615
 
616
- super().__init__()
616
+ super().__init__(
617
+ engine_type="sqlite",
618
+ min_version_number=3.25,
619
+ log_queries=log_queries,
620
+ log_responses=log_responses,
621
+ )
617
622
 
618
623
  @property
619
624
  def path(self):
@@ -1,6 +1,7 @@
1
1
  from .aggregate import Avg, Count, Max, Min, Sum
2
+ from .datetime import Day, Extract, Hour, Month, Second, Strftime, Year
2
3
  from .math import Abs, Ceil, Floor, Round
3
- from .string import Length, Lower, Ltrim, Reverse, Rtrim, Upper
4
+ from .string import Concat, Length, Lower, Ltrim, Reverse, Rtrim, Upper
4
5
  from .type_conversion import Cast
5
6
 
6
7
  __all__ = (
@@ -8,16 +9,25 @@ __all__ = (
8
9
  "Avg",
9
10
  "Cast",
10
11
  "Ceil",
12
+ "Concat",
11
13
  "Count",
14
+ "Day",
15
+ "Extract",
16
+ "Extract",
12
17
  "Floor",
18
+ "Hour",
13
19
  "Length",
14
20
  "Lower",
15
21
  "Ltrim",
16
22
  "Max",
17
23
  "Min",
24
+ "Month",
18
25
  "Reverse",
19
26
  "Round",
20
27
  "Rtrim",
28
+ "Second",
29
+ "Strftime",
21
30
  "Sum",
22
31
  "Upper",
32
+ "Year",
23
33
  )
@@ -0,0 +1,260 @@
1
+ import typing as t
2
+
3
+ from piccolo.columns.base import Column
4
+ from piccolo.columns.column_types import (
5
+ Date,
6
+ Integer,
7
+ Time,
8
+ Timestamp,
9
+ Timestamptz,
10
+ )
11
+ from piccolo.querystring import QueryString
12
+
13
+ from .type_conversion import Cast
14
+
15
+ ###############################################################################
16
+ # Postgres / Cockroach
17
+
18
+ ExtractComponent = t.Literal[
19
+ "century",
20
+ "day",
21
+ "decade",
22
+ "dow",
23
+ "doy",
24
+ "epoch",
25
+ "hour",
26
+ "isodow",
27
+ "isoyear",
28
+ "julian",
29
+ "microseconds",
30
+ "millennium",
31
+ "milliseconds",
32
+ "minute",
33
+ "month",
34
+ "quarter",
35
+ "second",
36
+ "timezone",
37
+ "timezone_hour",
38
+ "timezone_minute",
39
+ "week",
40
+ "year",
41
+ ]
42
+
43
+
44
+ class Extract(QueryString):
45
+ def __init__(
46
+ self,
47
+ identifier: t.Union[Date, Time, Timestamp, Timestamptz, QueryString],
48
+ datetime_component: ExtractComponent,
49
+ alias: t.Optional[str] = None,
50
+ ):
51
+ """
52
+ .. note:: This is for Postgres / Cockroach only.
53
+
54
+ Extract a date or time component from a ``Date`` / ``Time`` /
55
+ ``Timestamp`` / ``Timestamptz`` column. For example, getting the month
56
+ from a timestamp:
57
+
58
+ .. code-block:: python
59
+
60
+ >>> from piccolo.query.functions import Extract
61
+ >>> await Concert.select(
62
+ ... Extract(Concert.starts, "month", alias="start_month")
63
+ ... )
64
+ [{"start_month": 12}]
65
+
66
+ :param identifier:
67
+ Identifies the column.
68
+ :param datetime_component:
69
+ The date or time component to extract from the column.
70
+
71
+ """
72
+ if datetime_component.lower() not in t.get_args(ExtractComponent):
73
+ raise ValueError("The date time component isn't recognised.")
74
+
75
+ super().__init__(
76
+ f"EXTRACT({datetime_component} FROM {{}})",
77
+ identifier,
78
+ alias=alias,
79
+ )
80
+
81
+
82
+ ###############################################################################
83
+ # SQLite
84
+
85
+
86
+ class Strftime(QueryString):
87
+ def __init__(
88
+ self,
89
+ identifier: t.Union[Date, Time, Timestamp, Timestamptz, QueryString],
90
+ datetime_format: str,
91
+ alias: t.Optional[str] = None,
92
+ ):
93
+ """
94
+ .. note:: This is for SQLite only.
95
+
96
+ Format a datetime value. For example:
97
+
98
+ .. code-block:: python
99
+
100
+ >>> from piccolo.query.functions import Strftime
101
+ >>> await Concert.select(
102
+ ... Strftime(Concert.starts, "%Y", alias="start_year")
103
+ ... )
104
+ [{"start_month": "2024"}]
105
+
106
+ :param identifier:
107
+ Identifies the column.
108
+ :param datetime_format:
109
+ A string describing the output format (see SQLite's
110
+ `documentation <https://www.sqlite.org/lang_datefunc.html>`_
111
+ for more info).
112
+
113
+ """
114
+ super().__init__(
115
+ f"strftime('{datetime_format}', {{}})",
116
+ identifier,
117
+ alias=alias,
118
+ )
119
+
120
+
121
+ ###############################################################################
122
+ # Database agnostic
123
+
124
+
125
+ def _get_engine_type(identifier: t.Union[Column, QueryString]) -> str:
126
+ if isinstance(identifier, Column):
127
+ return identifier._meta.engine_type
128
+ elif isinstance(identifier, QueryString) and (
129
+ columns := identifier.columns
130
+ ):
131
+ return columns[0]._meta.engine_type
132
+ else:
133
+ raise ValueError("Unable to determine the engine type")
134
+
135
+
136
+ def _extract_component(
137
+ identifier: t.Union[Date, Time, Timestamp, Timestamptz, QueryString],
138
+ sqlite_format: str,
139
+ postgres_format: ExtractComponent,
140
+ alias: t.Optional[str],
141
+ ) -> QueryString:
142
+ engine_type = _get_engine_type(identifier=identifier)
143
+
144
+ return Cast(
145
+ (
146
+ Strftime(
147
+ identifier=identifier,
148
+ datetime_format=sqlite_format,
149
+ )
150
+ if engine_type == "sqlite"
151
+ else Extract(
152
+ identifier=identifier,
153
+ datetime_component=postgres_format,
154
+ )
155
+ ),
156
+ Integer(),
157
+ alias=alias,
158
+ )
159
+
160
+
161
+ def Year(
162
+ identifier: t.Union[Date, Timestamp, Timestamptz, QueryString],
163
+ alias: t.Optional[str] = None,
164
+ ) -> QueryString:
165
+ """
166
+ Extract the year as an integer.
167
+ """
168
+ return _extract_component(
169
+ identifier=identifier,
170
+ sqlite_format="%Y",
171
+ postgres_format="year",
172
+ alias=alias,
173
+ )
174
+
175
+
176
+ def Month(
177
+ identifier: t.Union[Date, Timestamp, Timestamptz, QueryString],
178
+ alias: t.Optional[str] = None,
179
+ ) -> QueryString:
180
+ """
181
+ Extract the month as an integer.
182
+ """
183
+ return _extract_component(
184
+ identifier=identifier,
185
+ sqlite_format="%m",
186
+ postgres_format="month",
187
+ alias=alias,
188
+ )
189
+
190
+
191
+ def Day(
192
+ identifier: t.Union[Date, Timestamp, Timestamptz, QueryString],
193
+ alias: t.Optional[str] = None,
194
+ ) -> QueryString:
195
+ """
196
+ Extract the day as an integer.
197
+ """
198
+ return _extract_component(
199
+ identifier=identifier,
200
+ sqlite_format="%d",
201
+ postgres_format="day",
202
+ alias=alias,
203
+ )
204
+
205
+
206
+ def Hour(
207
+ identifier: t.Union[Time, Timestamp, Timestamptz, QueryString],
208
+ alias: t.Optional[str] = None,
209
+ ) -> QueryString:
210
+ """
211
+ Extract the hour as an integer.
212
+ """
213
+ return _extract_component(
214
+ identifier=identifier,
215
+ sqlite_format="%H",
216
+ postgres_format="hour",
217
+ alias=alias,
218
+ )
219
+
220
+
221
+ def Minute(
222
+ identifier: t.Union[Time, Timestamp, Timestamptz, QueryString],
223
+ alias: t.Optional[str] = None,
224
+ ) -> QueryString:
225
+ """
226
+ Extract the minute as an integer.
227
+ """
228
+ return _extract_component(
229
+ identifier=identifier,
230
+ sqlite_format="%M",
231
+ postgres_format="minute",
232
+ alias=alias,
233
+ )
234
+
235
+
236
+ def Second(
237
+ identifier: t.Union[Time, Timestamp, Timestamptz, QueryString],
238
+ alias: t.Optional[str] = None,
239
+ ) -> QueryString:
240
+ """
241
+ Extract the second as an integer.
242
+ """
243
+ return _extract_component(
244
+ identifier=identifier,
245
+ sqlite_format="%S",
246
+ postgres_format="second",
247
+ alias=alias,
248
+ )
249
+
250
+
251
+ __all__ = (
252
+ "Extract",
253
+ "Strftime",
254
+ "Year",
255
+ "Month",
256
+ "Day",
257
+ "Hour",
258
+ "Minute",
259
+ "Second",
260
+ )
@@ -5,6 +5,12 @@ https://www.postgresql.org/docs/current/functions-string.html
5
5
 
6
6
  """
7
7
 
8
+ import typing as t
9
+
10
+ from piccolo.columns.base import Column
11
+ from piccolo.columns.column_types import Text, Varchar
12
+ from piccolo.querystring import QueryString
13
+
8
14
  from .base import Function
9
15
 
10
16
 
@@ -63,6 +69,44 @@ class Upper(Function):
63
69
  function_name = "UPPER"
64
70
 
65
71
 
72
+ class Concat(QueryString):
73
+ def __init__(
74
+ self,
75
+ *args: t.Union[Column, QueryString, str],
76
+ alias: t.Optional[str] = None,
77
+ ):
78
+ """
79
+ Concatenate multiple values into a single string.
80
+
81
+ .. note::
82
+ Null values are ignored, so ``null + '!!!'`` returns ``!!!``,
83
+ not ``null``.
84
+
85
+ .. warning::
86
+ For SQLite, this is only available in version 3.44.0 and above.
87
+
88
+ """
89
+ if len(args) < 2:
90
+ raise ValueError("At least two values must be passed in.")
91
+
92
+ placeholders = ", ".join("{}" for _ in args)
93
+
94
+ processed_args: t.List[t.Union[QueryString, Column]] = []
95
+
96
+ for arg in args:
97
+ if isinstance(arg, str) or (
98
+ isinstance(arg, Column)
99
+ and not isinstance(arg, (Varchar, Text))
100
+ ):
101
+ processed_args.append(QueryString("CAST({} AS TEXT)", arg))
102
+ else:
103
+ processed_args.append(arg)
104
+
105
+ super().__init__(
106
+ f"CONCAT({placeholders})", *processed_args, alias=alias
107
+ )
108
+
109
+
66
110
  __all__ = (
67
111
  "Length",
68
112
  "Lower",
@@ -70,4 +114,5 @@ __all__ = (
70
114
  "Reverse",
71
115
  "Rtrim",
72
116
  "Upper",
117
+ "Concat",
73
118
  )
@@ -14,7 +14,7 @@ class CreateIndex(DDL):
14
14
  def __init__(
15
15
  self,
16
16
  table: t.Type[Table],
17
- columns: t.List[t.Union[Column, str]],
17
+ columns: t.Union[t.List[Column], t.List[str]],
18
18
  method: IndexMethod = IndexMethod.btree,
19
19
  if_not_exists: bool = False,
20
20
  **kwargs,
@@ -14,7 +14,7 @@ class DropIndex(Query):
14
14
  def __init__(
15
15
  self,
16
16
  table: t.Type[Table],
17
- columns: t.List[t.Union[Column, str]],
17
+ columns: t.Union[t.List[Column], t.List[str]],
18
18
  if_exists: bool = True,
19
19
  **kwargs,
20
20
  ):
@@ -5,7 +5,7 @@ import typing as t
5
5
  from piccolo.columns.column_types import ForeignKey
6
6
  from piccolo.columns.combination import And, Where
7
7
  from piccolo.custom_types import Combinable, TableInstance
8
- from piccolo.engine.base import Batch
8
+ from piccolo.engine.base import BaseBatch
9
9
  from piccolo.query.base import Query
10
10
  from piccolo.query.methods.select import Select
11
11
  from piccolo.query.mixins import (
@@ -268,17 +268,17 @@ class Objects(
268
268
 
269
269
  ###########################################################################
270
270
 
271
- def first(self: Self) -> First[TableInstance]:
271
+ def first(self) -> First[TableInstance]:
272
272
  self.limit_delegate.limit(1)
273
273
  return First[TableInstance](query=self)
274
274
 
275
- def get(self: Self, where: Combinable) -> Get[TableInstance]:
275
+ def get(self, where: Combinable) -> Get[TableInstance]:
276
276
  self.where_delegate.where(where)
277
277
  self.limit_delegate.limit(1)
278
278
  return Get[TableInstance](query=First[TableInstance](query=self))
279
279
 
280
280
  def get_or_create(
281
- self: Self,
281
+ self,
282
282
  where: Combinable,
283
283
  defaults: t.Optional[t.Dict[Column, t.Any]] = None,
284
284
  ) -> GetOrCreate[TableInstance]:
@@ -288,17 +288,17 @@ class Objects(
288
288
  query=self, table_class=self.table, where=where, defaults=defaults
289
289
  )
290
290
 
291
- def create(self: Self, **columns: t.Any) -> Create[TableInstance]:
291
+ def create(self, **columns: t.Any) -> Create[TableInstance]:
292
292
  return Create[TableInstance](table_class=self.table, columns=columns)
293
293
 
294
294
  ###########################################################################
295
295
 
296
296
  async def batch(
297
- self: Self,
297
+ self,
298
298
  batch_size: t.Optional[int] = None,
299
299
  node: t.Optional[str] = None,
300
300
  **kwargs,
301
- ) -> Batch:
301
+ ) -> BaseBatch:
302
302
  if batch_size:
303
303
  kwargs.update(batch_size=batch_size)
304
304
  if node: