mirror of
https://github.com/coleifer/peewee.git
synced 2026-05-06 07:56:41 -04:00
Database docs also cleaned up postgres isolation level handling.
This commit is contained in:
+13
-6
@@ -620,8 +620,7 @@ Database
|
||||
:param bool register_unicode: Register unicode types.
|
||||
:param str encoding: Database encoding.
|
||||
:param int isolation_level: Isolation level constant, defined in the
|
||||
``psycopg2.extensions`` module or ``psycopg.connection.IsolationLevel``
|
||||
enum (psycopg3).
|
||||
``psycopg2.extensions`` module or ``psycopg.IsolationLevel`` enum (psycopg3).
|
||||
:param bool prefer_psycopg3: If both psycopg2 and psycopg3 are installed,
|
||||
instruct Peewee to prefer psycopg3.
|
||||
|
||||
@@ -633,21 +632,29 @@ Database
|
||||
Set the timezone on the current connection. If no connection is open,
|
||||
then one will be opened.
|
||||
|
||||
.. py:method:: set_isolation_level(isolation_level)
|
||||
|
||||
:param int isolation_level: Isolation level constant, defined in the
|
||||
``psycopg2.extensions`` module or ``psycopg.IsolationLevel`` enum (psycopg3).
|
||||
Set to ``None`` to use the server default.
|
||||
|
||||
.. py:method:: atomic(isolation_level=None)
|
||||
|
||||
:param str isolation_level: Isolation strategy: SERIALIZABLE, READ COMMITTED, REPEATABLE READ, READ UNCOMMITTED
|
||||
:param isolation_level: Isolation strategy: SERIALIZABLE, READ COMMITTED, REPEATABLE READ, READ UNCOMMITTED
|
||||
:type isolation_level: ``int`` or ``str``.
|
||||
|
||||
Create an atomic context-manager, optionally using the specified
|
||||
isolation level (if unspecified, the server default will be used).
|
||||
isolation level (if unspecified, the connection default will be used).
|
||||
|
||||
.. note:: Isolation level only applies to the outermost ``atomic()`` block.
|
||||
|
||||
.. py:method:: transaction(isolation_level=None)
|
||||
|
||||
:param str isolation_level: Isolation strategy: SERIALIZABLE, READ COMMITTED, REPEATABLE READ, READ UNCOMMITTED
|
||||
:param isolation_level: Isolation strategy: SERIALIZABLE, READ COMMITTED, REPEATABLE READ, READ UNCOMMITTED
|
||||
:type isolation_level: ``int`` or ``str``.
|
||||
|
||||
Create a transaction context-manager, optionally using the specified
|
||||
isolation level (if unspecified, the server default will be used).
|
||||
isolation level (if unspecified, the connection default will be used).
|
||||
|
||||
|
||||
.. py:class:: MySQLDatabase(database, **kwargs)
|
||||
|
||||
+681
-657
File diff suppressed because it is too large
Load Diff
@@ -3946,8 +3946,34 @@ class SqliteDatabase(Database):
|
||||
return fn.datetime(date_field, 'unixepoch')
|
||||
|
||||
|
||||
class Psycopg2Adapter(object):
|
||||
class _BasePsycopgAdapter(object):
|
||||
isolation_levels = {} # Map int -> str.
|
||||
|
||||
def __init__(self):
|
||||
self.isolation_levels_inv = {
|
||||
v: k for k, v in self.isolation_levels.items()}
|
||||
|
||||
def isolation_level_int(self, isolation_level):
|
||||
if isinstance(isolation_level, str):
|
||||
return self.isolation_levels_inv[isolation_level]
|
||||
return isolation_level
|
||||
|
||||
def isolation_level_str(self, isolation_level):
|
||||
if isinstance(isolation_level, int):
|
||||
return self.isolation_levels[isolation_level]
|
||||
return isolation_level
|
||||
|
||||
|
||||
class Psycopg2Adapter(_BasePsycopgAdapter):
|
||||
isolation_levels = {
|
||||
1: 'READ COMMITTED',
|
||||
2: 'REPEATABLE READ',
|
||||
3: 'SERIALIZABLE',
|
||||
4: 'READ UNCOMMITTED',
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
super(Psycopg2Adapter, self).__init__()
|
||||
self.json_type = Json_pg2
|
||||
self.jsonb_type = Json_pg2
|
||||
self.cast_json_case = True
|
||||
@@ -4005,8 +4031,16 @@ class Psycopg2Adapter(object):
|
||||
return fn.EXTRACT(NodeList((date_part, SQL('FROM'), date_field)))
|
||||
|
||||
|
||||
class Psycopg3Adapter(object):
|
||||
class Psycopg3Adapter(_BasePsycopgAdapter):
|
||||
isolation_levels = {
|
||||
1: 'READ UNCOMMITTED',
|
||||
2: 'READ COMMITTED',
|
||||
3: 'REPEATABLE READ',
|
||||
4: 'SERIALIZABLE',
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
super(Psycopg3Adapter, self).__init__()
|
||||
self.json_type = Json_pg3
|
||||
self.jsonb_type = Jsonb_pg3
|
||||
self.cast_json_case = False
|
||||
@@ -4084,7 +4118,6 @@ class PostgresqlDatabase(Database):
|
||||
isolation_level=None, **kwargs):
|
||||
self._register_unicode = register_unicode
|
||||
self._encoding = encoding
|
||||
self._isolation_level = isolation_level
|
||||
|
||||
prefer_psycopg3 = kwargs.pop('prefer_psycopg3', False)
|
||||
if psycopg is not None and prefer_psycopg3:
|
||||
@@ -4092,6 +4125,11 @@ class PostgresqlDatabase(Database):
|
||||
else:
|
||||
self._adapter = self.psycopg2_adapter()
|
||||
|
||||
# Accept a string ('READ COMMITTED') or an int constant. Since the
|
||||
# constants vary between psycopg2 & psycopg3 we have to abstract this.
|
||||
self._isolation_level = self._adapter.isolation_level_int(
|
||||
isolation_level)
|
||||
|
||||
super(PostgresqlDatabase, self).init(database, **kwargs)
|
||||
|
||||
def _connect(self):
|
||||
@@ -4137,7 +4175,8 @@ class PostgresqlDatabase(Database):
|
||||
if self.is_closed():
|
||||
self.connect()
|
||||
if isolation_level:
|
||||
stmt = 'BEGIN TRANSACTION ISOLATION LEVEL %s' % isolation_level
|
||||
txn_type = self._adapter.isolation_level_str(isolation_level)
|
||||
stmt = 'BEGIN TRANSACTION ISOLATION LEVEL %s' % txn_type
|
||||
else:
|
||||
stmt = 'BEGIN'
|
||||
with __exception_wrapper__:
|
||||
@@ -4282,6 +4321,10 @@ class PostgresqlDatabase(Database):
|
||||
def set_time_zone(self, timezone):
|
||||
self.execute_sql('set time zone "%s";' % timezone)
|
||||
|
||||
def set_isolation_level(self, isolation_level):
|
||||
self._isolation_level = self._adapter.isolation_level_int(
|
||||
isolation_level)
|
||||
|
||||
|
||||
class MySQLDatabase(Database):
|
||||
field_types = {
|
||||
|
||||
+9
-7
@@ -9,9 +9,11 @@ from playhouse.cockroachdb import PooledCockroachDatabase
|
||||
from playhouse.pool import PooledCySqliteDatabase
|
||||
from playhouse.pool import PooledMySQLDatabase
|
||||
from playhouse.pool import PooledPostgresqlDatabase
|
||||
from playhouse.pool import PooledPostgresqlExtDatabase
|
||||
from playhouse.pool import PooledPsycopg3Database
|
||||
from playhouse.pool import PooledSqliteDatabase
|
||||
from playhouse.pool import PooledSqliteExtDatabase
|
||||
from playhouse.postgres_ext import PostgresqlExtDatabase
|
||||
from playhouse.postgres_ext import Psycopg3Database
|
||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||
try:
|
||||
@@ -31,6 +33,10 @@ schemes = {
|
||||
'postgresql': PostgresqlDatabase,
|
||||
'postgres+pool': PooledPostgresqlDatabase,
|
||||
'postgresql+pool': PooledPostgresqlDatabase,
|
||||
'postgresext': PostgresqlExtDatabase,
|
||||
'postgresqlext': PostgresqlExtDatabase,
|
||||
'postgresext+pool': PooledPostgresqlExtDatabase,
|
||||
'postgresqlext+pool': PooledPostgresqlExtDatabase,
|
||||
'psycopg3': Psycopg3Database,
|
||||
'psycopg3+pool': PooledPsycopg3Database,
|
||||
'sqlite': SqliteDatabase,
|
||||
@@ -38,11 +44,6 @@ schemes = {
|
||||
'sqlite+pool': PooledSqliteDatabase,
|
||||
'sqliteext+pool': PooledSqliteExtDatabase,
|
||||
}
|
||||
if CySqliteDatabase is not None:
|
||||
schemes.update({
|
||||
'cysqlite': CySqliteDatabase,
|
||||
'cysqlite+pool': PooledCySqliteDatabase,
|
||||
})
|
||||
|
||||
def register_database(db_class, *names):
|
||||
global schemes
|
||||
@@ -136,8 +137,9 @@ else:
|
||||
register_database(APSWDatabase, 'apsw')
|
||||
|
||||
try:
|
||||
from playhouse.postgres_ext import PostgresqlExtDatabase
|
||||
from playhouse.cysqlite_ext import CySqliteDatabase
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
register_database(PostgresqlExtDatabase, 'postgresext', 'postgresqlext')
|
||||
register_database(CySqliteDatabase, 'cysqlite')
|
||||
register_database(PooledCySqliteDatabase, 'cysqlite+pool')
|
||||
|
||||
+21
-1
@@ -872,10 +872,30 @@ class TestPostgresIsolationLevel(DatabaseTestCase):
|
||||
|
||||
conn.set_isolation_level(2)
|
||||
self.assertEqual(conn.isolation_level, 2)
|
||||
|
||||
self.database.close()
|
||||
|
||||
conn = self.database.connection()
|
||||
self.assertEqual(conn.isolation_level, 3)
|
||||
self.database.close()
|
||||
|
||||
self.database.set_isolation_level(2)
|
||||
for _ in range(2):
|
||||
conn = self.database.connection()
|
||||
self.assertEqual(conn.isolation_level, 2)
|
||||
self.database.close()
|
||||
|
||||
def test_isolation_level_str(self):
|
||||
db = db_loader('postgres', isolation_level='SERIALIZABLE')
|
||||
conn = db.connection()
|
||||
self.assertEqual(conn.isolation_level,
|
||||
db._adapter.isolation_levels_inv['SERIALIZABLE'])
|
||||
db.close()
|
||||
|
||||
db.set_isolation_level('READ COMMITTED')
|
||||
conn = db.connection()
|
||||
self.assertEqual(conn.isolation_level,
|
||||
db._adapter.isolation_levels_inv['READ COMMITTED'])
|
||||
db.close()
|
||||
|
||||
|
||||
@skip_unless(pg12(), 'cte materialization requires pg >= 12')
|
||||
|
||||
Reference in New Issue
Block a user