plain.models 0.43.0__py3-none-any.whl → 0.44.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.
plain/models/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # plain-models changelog
2
2
 
3
+ ## [0.44.0](https://github.com/dropseed/plain/releases/plain-models@0.44.0) (2025-09-19)
4
+
5
+ ### What's changed
6
+
7
+ - PostgreSQL backup restoration now drops and recreates the database instead of using `pg_restore --clean`, providing more reliable restoration by terminating active connections and ensuring a completely clean database state ([a8865fe](https://github.com/dropseed/plain/commit/a8865fe5d6))
8
+ - Added `_meta` type annotation to the `Model` class for improved type checking and IDE support ([387b92e](https://github.com/dropseed/plain/commit/387b92e08b))
9
+
10
+ ### Upgrade instructions
11
+
12
+ - No changes required
13
+
3
14
  ## [0.43.0](https://github.com/dropseed/plain/releases/plain-models@0.43.0) (2025-09-12)
4
15
 
5
16
  ### What's changed
@@ -64,29 +64,47 @@ class PostgresBackupClient:
64
64
  cmd, env={**os.environ, **self.get_env()}, check=True, shell=True
65
65
  )
66
66
 
67
- def restore_backup(self, backup_path, *, pg_restore="pg_restore"):
67
+ def restore_backup(self, backup_path, *, pg_restore="pg_restore", psql="psql"):
68
68
  settings_dict = self.connection.settings_dict
69
69
 
70
- args = pg_restore.split()
71
- options = settings_dict.get("OPTIONS", {})
72
-
73
70
  host = settings_dict.get("HOST")
74
71
  port = settings_dict.get("PORT")
75
72
  dbname = settings_dict.get("NAME")
76
73
  user = settings_dict.get("USER")
77
- service = options.get("service")
78
74
 
79
- if not dbname and not service:
80
- # Connect to the default 'postgres' db.
81
- dbname = "postgres"
75
+ # Build common connection args
76
+ conn_args = []
82
77
  if user:
83
- args += ["-U", user]
78
+ conn_args += ["-U", user]
84
79
  if host:
85
- args += ["-h", host]
80
+ conn_args += ["-h", host]
86
81
  if port:
87
- args += ["-p", str(port)]
88
-
89
- args += ["--clean"] # Drop existing tables
82
+ conn_args += ["-p", str(port)]
83
+
84
+ # First, drop and recreate the database
85
+ # Connect to 'template1' database to do this (works for all databases including 'postgres')
86
+ drop_create_cmds = [
87
+ f"SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '{dbname}' AND pid <> pg_backend_pid()",
88
+ f'DROP DATABASE IF EXISTS "{dbname}"',
89
+ f'CREATE DATABASE "{dbname}"',
90
+ ]
91
+
92
+ for cmd in drop_create_cmds:
93
+ psql_args = (
94
+ psql.split()
95
+ + conn_args
96
+ + [
97
+ "-d",
98
+ "template1", # Always use template1
99
+ "-c",
100
+ cmd,
101
+ ]
102
+ )
103
+ subprocess.run(psql_args, env={**os.environ, **self.get_env()}, check=True)
104
+
105
+ # Now restore into the fresh database
106
+ args = pg_restore.split()
107
+ args += conn_args
90
108
  args += ["-d", dbname]
91
109
 
92
110
  # Using stdin/stdout let's us use executables from within a docker container too
plain/models/base.py CHANGED
@@ -193,6 +193,7 @@ class ModelState:
193
193
 
194
194
 
195
195
  class Model(metaclass=ModelBase):
196
+ _meta: Options
196
197
  DoesNotExist: type[ObjectDoesNotExist]
197
198
  MultipleObjectsReturned: type[MultipleObjectsReturned]
198
199
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plain.models
3
- Version: 0.43.0
3
+ Version: 0.44.0
4
4
  Summary: Model your data and store it in a database.
5
5
  Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
6
6
  License-File: LICENSE
@@ -1,9 +1,9 @@
1
1
  plain/models/AGENTS.md,sha256=xQQW-z-DehnCUyjiGSBfLqUjoSUdo_W1b0JmwYmWieA,209
2
- plain/models/CHANGELOG.md,sha256=yPHtgiBY7hwtydus3mAiT945vgMTO5c9pF64KC9V37s,14530
2
+ plain/models/CHANGELOG.md,sha256=xfDewS2Wt9gfbvC2fvpcZmQlaWAQCQ-YZ6aGLc69eHA,15141
3
3
  plain/models/README.md,sha256=lqzWJrEIxBCHC1P8X1YoRjbsMFlu0-kG4ujP76B_ZO4,8572
4
4
  plain/models/__init__.py,sha256=aB9HhIKBh0iK3LZztInAE-rDF-yKsdfcjfMtwtN5vnI,2920
5
5
  plain/models/aggregates.py,sha256=P0mhsMl1VZt2CVHMuCHnNI8SxZ9citjDLEgioN6NOpo,7240
6
- plain/models/base.py,sha256=Yp08EC4I0wQ65AXGNUe3mgM01zmuJ6B6XfFyCkcsmEc,66161
6
+ plain/models/base.py,sha256=APZ1K8hbiznIdW6GvzPC6o1LhofX-ggOPuMPcwZtqME,66180
7
7
  plain/models/cli.py,sha256=lhvlw7DVOU3CVoMUpHaj7qIbQ2d6qtSm_l9PdCeCnc0,36404
8
8
  plain/models/config.py,sha256=OF7eIEtXNZyGwgc3eMEpb5uEAup5RXeT-0um60dfBeU,636
9
9
  plain/models/connections.py,sha256=RBNa2FZ0x3C9un6PaYL-IYzH_OesRSpdHNGKvYHGiOM,2276
@@ -69,7 +69,7 @@ plain/models/backends/sqlite3/operations.py,sha256=K2PFCsvzGhBrPEzz1AXFenge2B4Ap
69
69
  plain/models/backends/sqlite3/schema.py,sha256=sbtI0PBGe0fK0IOFWh0bkpVntCMMVsfzPb9dpL7o4r8,22566
70
70
  plain/models/backups/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
71
71
  plain/models/backups/cli.py,sha256=AKVh_Go0LxnxFi2jQjmpPEbbJvYCurjJsGCWESm1X8A,2960
72
- plain/models/backups/clients.py,sha256=WQ4X4KrkNeiKYJcpGRwnfRiAeeyduHWEnq4tA4mtjvw,4047
72
+ plain/models/backups/clients.py,sha256=gHYQkukqamR_uksMr9wy3tBpMxK6DyUyj7nndNIlbo8,4744
73
73
  plain/models/backups/core.py,sha256=09IZUhBEe1Yej3PC8AidtkaI0c8tt7VnqGBCWK-WrFg,3318
74
74
  plain/models/fields/__init__.py,sha256=HrGTFOeG8Bt5pHWmiClmdn1qZcvCOIcXx4a5RKiIdr4,77938
75
75
  plain/models/fields/json.py,sha256=OdGW4EYBSHQgkuugB-EiIXOqGstUqcMKUvOTOVUHqEQ,18049
@@ -115,8 +115,8 @@ plain/models/sql/where.py,sha256=ezE9Clt2BmKo-I7ARsgqZ_aVA-1UdayCwr6ULSWZL6c,126
115
115
  plain/models/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
116
116
  plain/models/test/pytest.py,sha256=KD5-mxonBxOYIhUh9Ql5uJOIiC9R4t-LYfb6sjA0UdE,3486
117
117
  plain/models/test/utils.py,sha256=S3d6zf3OFWDxB_kBJr0tDvwn51bjwDVWKPumv37N-p8,467
118
- plain_models-0.43.0.dist-info/METADATA,sha256=1lUO79n5x4G0s1FzZinEIm5izVs3R-ii1NOR8ecaHvA,8884
119
- plain_models-0.43.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
120
- plain_models-0.43.0.dist-info/entry_points.txt,sha256=IYJAW9MpL3PXyXFWmKmALagAGXC_5rzBn2eEGJlcV04,112
121
- plain_models-0.43.0.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
122
- plain_models-0.43.0.dist-info/RECORD,,
118
+ plain_models-0.44.0.dist-info/METADATA,sha256=fzAPXuVnxvkoidy4MOMhKc4zDCrLW-Fl7uOzwKIJCbk,8884
119
+ plain_models-0.44.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
120
+ plain_models-0.44.0.dist-info/entry_points.txt,sha256=IYJAW9MpL3PXyXFWmKmALagAGXC_5rzBn2eEGJlcV04,112
121
+ plain_models-0.44.0.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
122
+ plain_models-0.44.0.dist-info/RECORD,,