1import operator
2from functools import cached_property
3
4from plain.models import transaction
5from plain.models.backends.base.features import BaseDatabaseFeatures
6from plain.models.db import OperationalError
7
8from .base import Database
9
10
11class DatabaseFeatures(BaseDatabaseFeatures):
12 minimum_database_version = (3, 21)
13 max_query_params = 999
14 supports_transactions = True
15 can_rollback_ddl = True
16 requires_literal_defaults = True
17 supports_temporal_subtraction = True
18 ignores_table_name_case = True
19 # Is "ALTER TABLE ... RENAME COLUMN" supported?
20 can_alter_table_rename_column = Database.sqlite_version_info >= (3, 25, 0)
21 # Is "ALTER TABLE ... DROP COLUMN" supported?
22 can_alter_table_drop_column = Database.sqlite_version_info >= (3, 35, 5)
23 supports_parentheses_in_compound = False
24 can_defer_constraint_checks = True
25 supports_over_clause = Database.sqlite_version_info >= (3, 25, 0)
26 supports_aggregate_filter_clause = Database.sqlite_version_info >= (3, 30, 1)
27 supports_order_by_nulls_modifier = Database.sqlite_version_info >= (3, 30, 0)
28 # NULLS LAST/FIRST emulation on < 3.30 requires subquery wrapping.
29 requires_compound_order_by_subquery = Database.sqlite_version_info < (3, 30)
30 order_by_nulls_first = True
31 supports_json_field_contains = False
32 supports_update_conflicts = Database.sqlite_version_info >= (3, 24, 0)
33 supports_update_conflicts_with_target = supports_update_conflicts
34
35 @cached_property
36 def supports_atomic_references_rename(self):
37 return Database.sqlite_version_info >= (3, 26, 0)
38
39 @cached_property
40 def supports_json_field(self):
41 with self.connection.cursor() as cursor:
42 try:
43 with transaction.atomic():
44 cursor.execute('SELECT JSON(\'{"a": "b"}\')')
45 except OperationalError:
46 return False
47 return True
48
49 can_introspect_json_field = property(operator.attrgetter("supports_json_field"))
50 has_json_object_function = property(operator.attrgetter("supports_json_field"))
51
52 @cached_property
53 def can_return_columns_from_insert(self):
54 return Database.sqlite_version_info >= (3, 35)
55
56 can_return_rows_from_bulk_insert = property(
57 operator.attrgetter("can_return_columns_from_insert")
58 )