plain.models 0.49.2__py3-none-any.whl → 0.50.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 (105) hide show
  1. plain/models/CHANGELOG.md +13 -0
  2. plain/models/aggregates.py +42 -19
  3. plain/models/backends/base/base.py +125 -105
  4. plain/models/backends/base/client.py +11 -3
  5. plain/models/backends/base/creation.py +22 -12
  6. plain/models/backends/base/features.py +10 -4
  7. plain/models/backends/base/introspection.py +29 -16
  8. plain/models/backends/base/operations.py +187 -91
  9. plain/models/backends/base/schema.py +267 -165
  10. plain/models/backends/base/validation.py +12 -3
  11. plain/models/backends/ddl_references.py +85 -43
  12. plain/models/backends/mysql/base.py +29 -26
  13. plain/models/backends/mysql/client.py +7 -2
  14. plain/models/backends/mysql/compiler.py +12 -3
  15. plain/models/backends/mysql/creation.py +5 -2
  16. plain/models/backends/mysql/features.py +24 -22
  17. plain/models/backends/mysql/introspection.py +22 -13
  18. plain/models/backends/mysql/operations.py +106 -39
  19. plain/models/backends/mysql/schema.py +48 -24
  20. plain/models/backends/mysql/validation.py +13 -6
  21. plain/models/backends/postgresql/base.py +41 -34
  22. plain/models/backends/postgresql/client.py +7 -2
  23. plain/models/backends/postgresql/creation.py +10 -5
  24. plain/models/backends/postgresql/introspection.py +15 -8
  25. plain/models/backends/postgresql/operations.py +109 -42
  26. plain/models/backends/postgresql/schema.py +85 -46
  27. plain/models/backends/sqlite3/_functions.py +151 -115
  28. plain/models/backends/sqlite3/base.py +37 -23
  29. plain/models/backends/sqlite3/client.py +7 -1
  30. plain/models/backends/sqlite3/creation.py +9 -5
  31. plain/models/backends/sqlite3/features.py +5 -3
  32. plain/models/backends/sqlite3/introspection.py +32 -16
  33. plain/models/backends/sqlite3/operations.py +125 -42
  34. plain/models/backends/sqlite3/schema.py +82 -58
  35. plain/models/backends/utils.py +52 -29
  36. plain/models/backups/cli.py +8 -6
  37. plain/models/backups/clients.py +16 -7
  38. plain/models/backups/core.py +24 -13
  39. plain/models/base.py +113 -74
  40. plain/models/cli.py +94 -63
  41. plain/models/config.py +1 -1
  42. plain/models/connections.py +23 -7
  43. plain/models/constraints.py +65 -47
  44. plain/models/database_url.py +1 -1
  45. plain/models/db.py +6 -2
  46. plain/models/deletion.py +66 -43
  47. plain/models/entrypoints.py +1 -1
  48. plain/models/enums.py +22 -11
  49. plain/models/exceptions.py +23 -8
  50. plain/models/expressions.py +440 -257
  51. plain/models/fields/__init__.py +253 -202
  52. plain/models/fields/json.py +120 -54
  53. plain/models/fields/mixins.py +12 -8
  54. plain/models/fields/related.py +284 -252
  55. plain/models/fields/related_descriptors.py +31 -22
  56. plain/models/fields/related_lookups.py +23 -11
  57. plain/models/fields/related_managers.py +81 -47
  58. plain/models/fields/reverse_related.py +58 -55
  59. plain/models/forms.py +89 -63
  60. plain/models/functions/comparison.py +71 -18
  61. plain/models/functions/datetime.py +79 -29
  62. plain/models/functions/math.py +43 -10
  63. plain/models/functions/mixins.py +24 -7
  64. plain/models/functions/text.py +104 -25
  65. plain/models/functions/window.py +12 -6
  66. plain/models/indexes.py +52 -28
  67. plain/models/lookups.py +228 -153
  68. plain/models/migrations/autodetector.py +86 -43
  69. plain/models/migrations/exceptions.py +7 -3
  70. plain/models/migrations/executor.py +33 -7
  71. plain/models/migrations/graph.py +79 -50
  72. plain/models/migrations/loader.py +45 -22
  73. plain/models/migrations/migration.py +23 -18
  74. plain/models/migrations/operations/base.py +37 -19
  75. plain/models/migrations/operations/fields.py +89 -42
  76. plain/models/migrations/operations/models.py +245 -143
  77. plain/models/migrations/operations/special.py +82 -25
  78. plain/models/migrations/optimizer.py +7 -2
  79. plain/models/migrations/questioner.py +58 -31
  80. plain/models/migrations/recorder.py +18 -11
  81. plain/models/migrations/serializer.py +50 -39
  82. plain/models/migrations/state.py +220 -133
  83. plain/models/migrations/utils.py +29 -13
  84. plain/models/migrations/writer.py +17 -14
  85. plain/models/options.py +63 -56
  86. plain/models/otel.py +16 -6
  87. plain/models/preflight.py +35 -12
  88. plain/models/query.py +323 -228
  89. plain/models/query_utils.py +93 -58
  90. plain/models/registry.py +34 -16
  91. plain/models/sql/compiler.py +146 -97
  92. plain/models/sql/datastructures.py +38 -25
  93. plain/models/sql/query.py +255 -169
  94. plain/models/sql/subqueries.py +32 -21
  95. plain/models/sql/where.py +54 -29
  96. plain/models/test/pytest.py +15 -11
  97. plain/models/test/utils.py +4 -2
  98. plain/models/transaction.py +20 -7
  99. plain/models/utils.py +13 -5
  100. {plain_models-0.49.2.dist-info → plain_models-0.50.0.dist-info}/METADATA +1 -1
  101. plain_models-0.50.0.dist-info/RECORD +122 -0
  102. plain_models-0.49.2.dist-info/RECORD +0 -122
  103. {plain_models-0.49.2.dist-info → plain_models-0.50.0.dist-info}/WHEEL +0 -0
  104. {plain_models-0.49.2.dist-info → plain_models-0.50.0.dist-info}/entry_points.txt +0 -0
  105. {plain_models-0.49.2.dist-info → plain_models-0.50.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,13 +1,20 @@
1
+ from __future__ import annotations
2
+
1
3
  import gzip
2
4
  import os
3
5
  import subprocess
6
+ from pathlib import Path
7
+ from typing import TYPE_CHECKING
8
+
9
+ if TYPE_CHECKING:
10
+ from plain.models.backends.base.base import BaseDatabaseWrapper
4
11
 
5
12
 
6
13
  class PostgresBackupClient:
7
- def __init__(self, connection):
14
+ def __init__(self, connection: BaseDatabaseWrapper) -> None:
8
15
  self.connection = connection
9
16
 
10
- def get_env(self):
17
+ def get_env(self) -> dict[str, str]:
11
18
  settings_dict = self.connection.settings_dict
12
19
  options = settings_dict.get("OPTIONS", {})
13
20
  env = {}
@@ -27,7 +34,7 @@ class PostgresBackupClient:
27
34
  env["PGSSLKEY"] = str(options.get("sslkey"))
28
35
  return env
29
36
 
30
- def create_backup(self, backup_path, *, pg_dump="pg_dump"):
37
+ def create_backup(self, backup_path: Path, *, pg_dump: str = "pg_dump") -> None:
31
38
  settings_dict = self.connection.settings_dict
32
39
 
33
40
  args = pg_dump.split()
@@ -64,7 +71,9 @@ class PostgresBackupClient:
64
71
  cmd, env={**os.environ, **self.get_env()}, check=True, shell=True
65
72
  )
66
73
 
67
- def restore_backup(self, backup_path, *, pg_restore="pg_restore", psql="psql"):
74
+ def restore_backup(
75
+ self, backup_path: Path, *, pg_restore: str = "pg_restore", psql: str = "psql"
76
+ ) -> None:
68
77
  settings_dict = self.connection.settings_dict
69
78
 
70
79
  host = settings_dict.get("HOST")
@@ -118,17 +127,17 @@ class PostgresBackupClient:
118
127
 
119
128
 
120
129
  class SQLiteBackupClient:
121
- def __init__(self, connection):
130
+ def __init__(self, connection: BaseDatabaseWrapper) -> None:
122
131
  self.connection = connection
123
132
 
124
- def create_backup(self, backup_path):
133
+ def create_backup(self, backup_path: Path) -> None:
125
134
  self.connection.ensure_connection()
126
135
  src_conn = self.connection.connection
127
136
  dump = "\n".join(src_conn.iterdump())
128
137
  with gzip.open(backup_path, "wt") as f:
129
138
  f.write(dump)
130
139
 
131
- def restore_backup(self, backup_path):
140
+ def restore_backup(self, backup_path: Path) -> None:
132
141
  with gzip.open(backup_path, "rt") as f:
133
142
  sql = f.read()
134
143
 
@@ -1,18 +1,29 @@
1
+ from __future__ import annotations
2
+
1
3
  import datetime
2
4
  import os
5
+ from collections.abc import Generator
3
6
  from pathlib import Path
7
+ from typing import TYPE_CHECKING, Any, cast
4
8
 
5
9
  from plain.runtime import PLAIN_TEMP_PATH
6
10
 
7
- from .. import db_connection
11
+ from .. import db_connection as _db_connection
8
12
  from .clients import PostgresBackupClient, SQLiteBackupClient
9
13
 
14
+ if TYPE_CHECKING:
15
+ from plain.models.backends.base.base import BaseDatabaseWrapper
16
+
17
+ db_connection = cast("BaseDatabaseWrapper", _db_connection)
18
+ else:
19
+ db_connection = _db_connection
20
+
10
21
 
11
22
  class DatabaseBackups:
12
- def __init__(self):
23
+ def __init__(self) -> None:
13
24
  self.path = PLAIN_TEMP_PATH / "backups"
14
25
 
15
- def find_backups(self):
26
+ def find_backups(self) -> list[DatabaseBackup]:
16
27
  if not self.path.exists():
17
28
  return []
18
29
 
@@ -27,20 +38,20 @@ class DatabaseBackups:
27
38
 
28
39
  return backups
29
40
 
30
- def create(self, name, **create_kwargs):
41
+ def create(self, name: str, **create_kwargs: Any) -> Path:
31
42
  backup = DatabaseBackup(name, backups_path=self.path)
32
43
  if backup.exists():
33
44
  raise Exception(f"Backup {name} already exists")
34
45
  backup_dir = backup.create(**create_kwargs)
35
46
  return backup_dir
36
47
 
37
- def restore(self, name, **restore_kwargs):
48
+ def restore(self, name: str, **restore_kwargs: Any) -> None:
38
49
  backup = DatabaseBackup(name, backups_path=self.path)
39
50
  if not backup.exists():
40
51
  raise Exception(f"Backup {name} not found")
41
52
  backup.restore(**restore_kwargs)
42
53
 
43
- def delete(self, name):
54
+ def delete(self, name: str) -> None:
44
55
  backup = DatabaseBackup(name, backups_path=self.path)
45
56
  if not backup.exists():
46
57
  raise Exception(f"Backup {name} not found")
@@ -48,17 +59,17 @@ class DatabaseBackups:
48
59
 
49
60
 
50
61
  class DatabaseBackup:
51
- def __init__(self, name: str, *, backups_path: Path):
62
+ def __init__(self, name: str, *, backups_path: Path) -> None:
52
63
  self.name = name
53
64
  self.path = backups_path / name
54
65
 
55
66
  if not self.name:
56
67
  raise ValueError("Backup name is required")
57
68
 
58
- def exists(self):
69
+ def exists(self) -> bool:
59
70
  return self.path.exists()
60
71
 
61
- def create(self, **create_kwargs):
72
+ def create(self, **create_kwargs: Any) -> Path:
62
73
  self.path.mkdir(parents=True, exist_ok=True)
63
74
 
64
75
  backup_path = self.path / "default.backup"
@@ -75,7 +86,7 @@ class DatabaseBackup:
75
86
 
76
87
  return self.path
77
88
 
78
- def iter_files(self):
89
+ def iter_files(self) -> Generator[Path, None, None]:
79
90
  for backup_file in self.path.iterdir():
80
91
  if not backup_file.is_file():
81
92
  continue
@@ -83,7 +94,7 @@ class DatabaseBackup:
83
94
  continue
84
95
  yield backup_file
85
96
 
86
- def restore(self, **restore_kwargs):
97
+ def restore(self, **restore_kwargs: Any) -> None:
87
98
  for backup_file in self.iter_files():
88
99
  if db_connection.vendor == "postgresql":
89
100
  PostgresBackupClient(db_connection).restore_backup(
@@ -95,12 +106,12 @@ class DatabaseBackup:
95
106
  else:
96
107
  raise Exception("Unsupported database vendor")
97
108
 
98
- def delete(self):
109
+ def delete(self) -> None:
99
110
  for backup_file in self.iter_files():
100
111
  backup_file.unlink()
101
112
 
102
113
  self.path.rmdir()
103
114
 
104
- def updated_at(self):
115
+ def updated_at(self) -> datetime.datetime:
105
116
  mtime = os.path.getmtime(self.path)
106
117
  return datetime.datetime.fromtimestamp(mtime)